Adapter Pattern vs Liskov Substitution
The Adapter design pattern is used to convert the interface of a class (Target) into another interface (Adaptee) clients expect. Adapter lets incompatible classes work together that could not otherwise because of their incompatible interfaces.
The Adapter Pattern can be implemented in two ways, by Inheritance (class version of Adapter pattern) and by Composition (object version of Adapter pattern).
My question is about the class version of adapter pattern which is implemented using Inheritance.
Here is an example of Drawing 开发者_JAVA百科Editor:
interface Shape
{
Rectangle BoundingBox();
Manipulator CreateManipulator();
}
class TextView
{
public TextView() { }
public Point GetOrigin() { }
public int GetWidth() { }
public int GetHeight() { }
}
interface Shape
{
Rectangle BoundingBox();
Manipulator CreateManipulator();
}
class TextView
{
public TextView() { }
public Point GetOrigin() { }
public int GetWidth() { }
public int GetHeight() { }
}
We would like to reuse TextView class to implement TextShape, but the interfaces are different, and therefore, TextView and Shape objects cannot be used interchangeably.
Should one change the TextView class to conform to the shape interface? Perhaps not.
TextShape can adapt the TextView interface to the shape's interface, in one of the two ways:
- By inheriting Shape's interface and TextView's implementation (class version of Adapter patter)
- By composing a TextView instance inside the TextShape object and implementing the TextShape's interface by using the TextView instance (object version of Adapter pattern).
Class Adapter
interface Shape
{
Rectangle BoundingBox();
Manipulator CreateManipulator();
}
class TextView
{
public TextView() { }
public Point GetOrigin() { }
public int GetWidth() { }
public int GetHeight() { }
}
class TextShape : TextView, Shape
{
public Rectangle BoundingBox()
{
Rectangle rectangle;
int x, y;
Point p = GetOrigin();
x = GetWidth();
y = GetHeight();
//...
return rectangle;
}
#region Shape Members
public Rectangle Shape.BoundingBox()
{
return new TextBoundingBox();
}
public Manipulator Shape.CreateManipulator()
{
return new TextManipulator();
}
#endregion
}
Now for the question :-). Is TextShape inheriting from Shape and particularly from TextView a valid "is a" relationship? And if not, doesn't it violate Liskov's Substitution Principle?
It doesn't violate the Liskov Substitution Principle unless you have something in the subclass that makes it behave in a way that doesn't make sense for the superclass (violating the contract of the superclass). This is incomplete code of course, but I don't see any sign of that.
It might violate the Single Responsibility Principle, but I'm not sure that's a giant concern in an adapter implementation.
I'd generally prefer the delegate way.
精彩评论