设计模式之Adapter模式
说起Adapter,STL里的stack和queue都是adapter,底层是deque,隐藏了deque的一些接口,使得其可以达到FIFO是queue,LIFO是stack。
The STL stack is a container adaptor. That is, it is not a "first-class" container, but instead simply "adapts" one of the sequential first-class containers (by default, the deque) for its own purposes. So, the deque interface is restricted (i.e., much of it is hidden) so that the required LIFO (Last In, First Out) stack-like behavior is provided.
再说通透一点,adapter就是适配器,电源适配器知道吧,把220v交流电转换为笔记本可接受的电压和电流就是我们常见的电源适配器,手机电源适配器等等。
还有STL里本来就有一类叫做adapter,有容器adapter即stack和queue,还有迭代器的adapter,有insert iterators,reverse iterators,iostream iterators,还有仿函数的functor adapters,我印象比较深的仿函数adapter就是,可以给二元操作给一个参数也能用,等等。。STL里都写的比较清楚。这里就不赘述了。
正题:
Adapter适配器模式是将两个不兼容的类组合在一起使用。适配器起到一种转换和包装的作用。
Adapter设计模式主要目的组合两个不相干类,常用有两种方法:第一种解决方案是修改各自类的接口。但是如果没有源码,或者不愿意为了一个应用而修改各自的接口,则需要使用Adapter适配器,在两种接口之间创建一个混合接口。
Adapter适配器设计模式中有3个重要角色:被适配者Adaptee,适配器Adapter和目标对象Target。其中两个现存的想要组合到一起的类分别是被适配者Adaptee和目标对象Target角色,我们需要创建一个适配器Adapter将其组合在一起。
实现Adapter适配器设计模式有两种方式:组合(compositon, has-a关系)和继承(inheritance,is-a关系)。
对象适配器模式使用组合,UML图如下:
利用组合实现的Adapter模式:
就是Aapter里实际上包含一个被适配的对象。(组合)又继承了target。因此如果要用到target的方法,直接调用父类的方法,如果要用到被适配者的方法, 就调用内部成员的函数。
//圆形,目标对象 class Cirecle{ public void drawCircle(){ System.out.println(“Draw circle”); } } //方形,被适配对象 class Square{ public void drawSquare(){ System.out.println(“Draw square”); } } //既可以画圆形,又可以画方形,适配器 public class HybridShape extends Circle{ private Square square; public HybridShape(Square square){ this.square = square; } public void drawSquare(){ square.drawSquare(); } } interface ICircle{ public void drawCircle(); } interface ISquare{ public void drawSquare(); } //圆形 class Cirecle implements ICircle{ public void drawCircle(){ System.out.println(“Draw circle”); } } //方形 class Square implements ISquare{ public void drawSquare(){ System.out.println(“Draw square”); } } //既可以画圆形,又可以画方形,适配器 public class HybridShape implements ICircle, ISquare{ private ISquare square; private ICircle circle; public HybridShape(Square square){ this.square = square; } public HybridShape(Circle circle){ this.circle = circle; } public void drawSquare(){ square.drawSquare(); } public void drawCircle(){ circle.drawCircle(); } }
利用多继承方式实现Adapter模式,java里不支持多继承,但是可以用interface实现。
先上类图:
可以看到Adapter同时继承了target和adaptee。
4 //目标接口类,客户需要的接口 5 class Target 6 { 7 public: 8 Target(); 9 virtual ~Target(); 10 virtual void Request();//定义标准接口 11 }; 12 13 //需要适配的类 14 class Adaptee 15 { 16 public: 17 Adaptee(); 18 ~Adaptee(); 19 void SpecificRequest(); 20 }; 21 22 //类模式,适配器类,通过public继承获得接口继承的效果,通过private继承获得实现继承的效果 23 class Adapter:public Target,private Adaptee 24 { 25 public: 26 Adapter(); 27 ~Adapter(); 28 virtual void Request();//实现Target定义的Request接口 29 }; 6 Target::Target() 7 {} 8 9 Target::~Target() 10 {} 11 12 void Target::Request() 13 { 14 cout << "Target::Request()" << endl; 15 } 16 17 Adaptee::Adaptee() 18 { 19 } 20 21 Adaptee::~Adaptee() 22 { 23 } 24 25 void Adaptee::SpecificRequest() 26 { 27 cout << "Adaptee::SpecificRequest()" << endl; 28 } 29 30 //类模式的Adapter 31 Adapter::Adapter() 32 { 33 } 34 35 Adapter::~Adapter() 36 { 37 } 38 39 void Adapter::Request() 40 { 41 cout << "Adapter::Request()" << endl; 42 this->SpecificRequest(); 43 cout << "----------------------------" <<endl; 44 }
在Adapter模式的两种模式中,有一个很重要的概念就是接口继承和实现继承的区别和联系。接口继承和实现继承是面向对象领域的两个重要的概念,接口继承指的是通过继承,子类获得了父类的接口,而实现继承指的是通过继承子类获得了父类的实现(并不统共接口)。在C++中的public继承既是接口继承又是实现继承,因为子类在继承了父类后既可以对外提供父类中的接口操作,又可以获得父类的接口实现。当然我们可以通过一定的方式和技术模拟单独的接口继承和实现继承,例如我们可以通过private继承获得实现继承的效果(private继承后,父类中的接口都变为private,当然只能是实现继承了。),通过纯抽象基类模拟接口继承的效果,但是在C++中pure virtual function也可以提供默认实现(effective C++中好像有?),因此这是不纯正的接口继承,但是在Java中我们可以interface来获得真正的接口继承了。