首页 > 代码库 > 适配器模式

适配器模式

1. 概述

  将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。

  比如说小王拥有2种技能分别是说日语和说英语,而某个岗位(目标)需要你同时回说日语、英语、和法语,那么需要把小王适配到这个岗位,就需要添加一个说法语的方法,这样才能满足目标的需要。

2. 解决的问题

  即Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。

3. 角色

  1)目标接口(Target):客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口。

  2) 需要适配的类(Adaptee):需要适配的类或适配者类。

  3) 适配器(Adapter):通过包装一个需要适配的对象,把原接口转换成目标接口。 

4. 适用情况

  适配器模式主要用于几种情况:

  1)系统需要使用现有的类,而这些类的接口不符合系统的接口。

  2)想要建立一个可以重用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。

  3)两个类所做的事情相同或相似,但是具有不同接口的时候。

  4)旧的系统开发的类已经实现了一些功能,但是客户端却只能以另外接口的形式访问,但我们不希望手动更改原有类的时候。

  5)使用第三方组件,组件接口定义和自己定义的不同,不希望修改自己的接口,但是要使用第三方组件接口的功能。

5. 优缺点

  优点:

  1)通过适配器,客户端可以调用同一接口,因而对客户端来说是透明的。这样做更简单、更直接、更紧凑。

  2)复用了现存的类,解决了现存类和复用环境要求不一致的问题。

  3)将目标类和适配者类解耦,通过引入一个适配器类重用现有的适配者类,而无需修改原有代码。

  4)一个对象适配器可以把多个不同的适配者类适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。

  缺点

  1)对于对象适配器来说,更换适配器的实现过程比较复杂。

  以上,参考http://www.cnblogs.com/wangjq/archive/2012/07/09/2582485.html

6. 分类

  1)类适配器

技术分享

  由图中可以看出,Adaptee类没有Request方法,而客户期待这个方法。为了使客户能够使用Adaptee类,提供一个中间环节,即类Adapter类,Adapter类实现了Target接口,并继承自Adaptee,Adapter类的Request方法重新封装了Adaptee的SpecificRequest方法,实现了适配的目的。

  因为Adapter与Adaptee是继承的关系,所以这决定了这个适配器模式是类的。

 1 #ifndef _ADAPTER_H_ 2 #define _ADAPTER_H_ 3  4 //目标接口类,客户需要的接口 5 class Target 6 { 7 public: 8     Target(); 9     virtual ~Target();10     virtual void Request(){}11 };12 13 //需要适配的类14 class Adaptee15 {16 public:17     Adaptee();18     ~Adaptee();19     void SpecificRequest()20     {21         cout << "Adaptee::SpecificRequest()" << endl;22     }23 };24 25 //类模式,适配器类,通过public继承获得接口继承的效果,通过private继承获得实现继承的效果26 class Adapter:public Target,private Adaptee27 {28 public:29     Adapter();30     ~Adapter();31     //实现Target定义的Request接口32     virtual void Request()33     {34          this->SpecificRequest();  35     }36 };37 38 int main()  39 {  40     // Create adapter and place a request  41     Target *t = new Adapter();  42     t->Request();  43       44     return 0;  45 }46 #endif

  2)对象适配器:

技术分享

  客户端需要调用Request方法,而Adaptee没有该方法,为了使客户端能够使用Adaptee类,需要提供一个包装(Wrapper)类Adapter。这个包装类包装了一个Adaptee的实例,从而将客户端与Adaptee衔接起来。由于Adapter与Adaptee是委派关系,这决定了这个适配器模式是对象的。

 1 #include<iostream>   2 using namespace std;   3        4 // "ITarget"   5 class Target   6 {   7 public:   8     // Methods   9     virtual void Request(){};  10 };  11       12 // "Adaptee"  13 class Adaptee  14 {  15 public:  16     // Methods  17     void SpecificRequest()  18     {  19         cout<<"Called SpecificRequest()"<<endl;  20     }  21 };  22       23 // "Adapter"  24 class Adapter : public Target  25 {  26 private:  27     Adaptee *adaptee;  28       29 public:  30     Adapter()  31     {  32         adaptee = new Adaptee();  33     }  34       35     // Implements ITarget interface  36     void Request()  37     {  38         // Possibly do some data manipulation  39         // and then call SpecificRequest    40         adaptee->SpecificRequest();  41     }  42 };  43       44       45 int main()  46 {  47     // Create adapter and place a request  48     Target *t = new Adapter();  49     t->Request();  50       51     return 0;  52 }

  3) 缺省适配器模式:

  缺省适配器模式是一种特殊的适配器模式,但这个适配器是由一个抽象类实现的,并且在抽象类中要实现目标接口中所规定的所有方法,但很多方法的实现都是“平庸”的实现,也就是说,这些方法都是空方法。而具体的子类都要继承此抽象类。

 1 #include<iostream>   2 using namespace std;   3        4        5 class Target {    6 public:   7     virtual void f1(){};    8     virtual void f2(){};    9     virtual void f3(){};     10 };  11       12 class DefaultAdapter : public Target   13 {   14 public:  15     void f1() {   16     }   17       18     void f2() {   19     }   20       21     void f3() {   22     }   23 };  24       25 class MyInteresting :public DefaultAdapter  26 {   27 public:  28      void f3(){         29         cout<<"呵呵,我就对f3()方法感兴趣,别的不管了!"<<endl;  30     }   31 };  32       33 int main()  34 {  35     // Create adapter and place a request  36     Target *t = new MyInteresting();  37     t->f3();  38       39     return 0;  40 }

  以上,参考http://tech.ddvip.com/2013-05/1369314244196006.html

适配器模式