适配器模式与里氏替换
Adapter设计模式用于将一个类(Target)的接口转换为客户期望的另一个接口(Adaptee)。适配器允许不兼容的类一起工作,否则这些类由于接口不兼容而无法一起工作。
适配器模式可以通过两种方式实现:继承(适配器模式的类版本)和组合(适配器模式的对象版本)。
我的问题是关于使用继承实现的适配器模式的类版本。
下面是绘图编辑器的示例:
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() { }
}
我们想重用 TextView 类来实现 TextShape,但接口是不同,因此 TextView 和 Shape 对象不能互换使用。
是否应该更改 TextView 类以符合形状接口?也许不是。
TextShape 可以通过以下两种方式之一使 TextView 接口适应形状的接口:
- 通过继承 Shape 的接口和 TextView 的实现(Adapter 模式的类版本)
- 通过在 TextShape 对象内部组合 TextView 实例并使用 TextView 实现 TextShape 的接口实例(适配器模式的对象版本)。
类适配器
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
}
现在回答问题:-)。 TextShape 从 Shape 继承,特别是从 TextView 继承,是否存在有效的“is a”关系?如果不是,那不是违反了里氏替代原则吗?
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 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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
它不会违反里氏替换原则,除非子类中有一些东西使它的行为方式对超类没有意义(违反了超类的契约)。这当然是不完整的代码,但我没有看到任何迹象。
它可能违反单一职责原则,但我不确定这是适配器中的一个巨大问题执行。
我通常更喜欢委托方式。
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.