Java api 中设计模式之适配器模式(Adapter)
简介:
在java.awt.event. java.swing.event包中,java提供了使用适配器设计模式的若干个类。这些类的对象充当产生特定事件的对象和那些处理这些事件的对象之间的适配器。比如说,MouseAdapter使得一个产生MouseEvent的对象适应于一个处理该事件的对象。
适配器设计模式为对象提供一个适应于其它对象接口的新接口,允许两个对象之间彼此进行协作。
适配器与电子设备上的插头转接器相类似----欧洲生产的电子插座与美国生产的不同,因此需要转接器来将美国设备插接到欧洲产的电子插座上。
意图:
将一个类的接口转换成客户期望的另一个类的接口。使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
动机:
有时,为复用而设计的工具箱类不能够被复用的原因仅仅是因为它的接口与专业应用领域所需要的接口不匹配。
例如,有一个绘图编辑器,这个编辑器允许用户绘制和排列图形对象来生成图片和图表。图形对象有一个可编辑的形状,并可以绘制自身。图形对象的接口由一个称为Shape的抽象类定义。每一种图形对象都是Shape类的子类。例如,LineShape,PolygonShape等等。现在我们需要一个TextShape,由于要涉及到复杂的屏幕刷新和缓冲区管理,所以比较复杂。现在有一个现成的TextView类可以显示和编辑正文。我们自然想到可以复用这个TextView类实现TextShape该多好呀。因为TextView设计的时候不知道Shape接口的存在,所以它们不能互换。
一个应用中可能会有一些类具有不同的接口并且这些接口互不兼容,在这样的应用中,如何使具有不同接口的类协同工作呢?我们可以定义一个TextShape类,由它来适配TextView的接口和Shape的接口。可以有两种方法来做这件事:1,继承Shape类的接口和TextView类的实现(Adapter模式的类版本)2,将一个TextView实例作为TextShape的组成部分,并且使用TextView的接口来实现TextShape(Adapter模式的对象版本)
实现:
类版本。
class Shape {
public:
Shape();
virtual void SoundingBox(Point& bottomLeft, Point& topRight) const;
virtual Manipulator* createManipulator() const;
};
class Textview {
public:
TextView();
void GetOrign(Coord& x, Coord& y) const;
void GetExtent(Coord& width, Coord& height) const;
virtual bool IsEmpty() const;
};
class TextShape : public Shape, private Textview {
public:
TextShape();
virtual void BoundingBox(Point& bottomLeft, Point& topRight) const;
virtual bool IsEmpty() const;
virtual Manipulator* CreateManipulator() const;
};
void TextShape::BoundingBox(Point& bottomLeft, Point& topRight) const{
Coord bottom, left, width, height;
GetOrigin(bottom, left);
GetExtent(width, height);
bottomLeft = Point(bottom, left);
topRight = Point(bottom + width, left + height);
}
bool TextShape::IsEmpty() const{
return TextView::IsEmpty();
}
Manipulator * CreateManipulator() const {
return new TextManipulator(this);
}
对象模式:
class TextShape : public Shape {
public:
TextShape(TextView *);
virtual void BoundingBox(Point& bottomLeft, Point& topRight) const;
virtual bool IsEmpty() const;
virtual Manipulator* CreateManipulator() const;
private:
TextView * _text;
};
TextShape::TextShape(TextView *t){
_text = t;
}
void TextShape::BoundingBox(Point& bottomLeft, Point& topRight) const{
Coord bottom, left, width, height;
_text->GetOrigin(bottom, left);
_text->GetExtent(width, height);
bottomLeft = Point(bottom, left);
topRight = Point(bottom + width, left + height);
}
bool TextShape::IsEmpty() const {
return _text->IsEmpty();
};
Manipulator * CreateManipulator() const {
return new TextManipulator(this);
}
将这段代码与类版本的适配器代码进行比较,可以看出编写对象适配器代码相对麻烦一些,但是它比较灵活。例如, 客户仅需将TextView子类的一个实例传给TextShape类的构造函数,对象适配器版本的TextShape就同样可以与TextView子类一起很好的工作。但是如果用类版本的代码来使得TextShape与TextView子类一起工作,还得重新定义TextShape类。所以对象版本是非常灵活的,也是推荐的。