[学习笔记]设计模式之Adapter

写在前面

为方便读者,本文已添加至索引html

Adapter(适配器)模式主要解决接口不匹配的问题。为此,让咱们要回到最初Builder模式建立平行世界时,白雪公主和小霍比特人的谜之相遇。在这个世界里,咱们暂时有见到两个种族Human和Hobbit。种族不一样所产生的最大区别是什么?固然个头是一部分,也仅仅是一部分而已。毕竟Human里也有怎么长都才那么高的吧:P。这里要说的区别是:他们的语言不通。是的,白雪公主一开始根本就听不懂小霍比特人在说什么。设计模式

在这个平行世界中,全部的Human通用语是中文,(为何是中文!由于全世界都在学中国话。)包括白雪公主(你知道我是必定不会忠于原著的)。而霍比特人,咱们假定他们用的是霍比特语。因此你们在表达“打招呼”的意思时,用的是彻底不一样的语言:学习

 1 class Human {
 2 public:
 3     // ... other action ...
 4     virtual void hello() { cout << "你好!" << endl; }
 5 }
 6 
 7 class Hobbit {
 8 public:
 9     // ... other action ...
10     virtual void hohobi() { cout << "HOhoBI*" << endl; }
11 }

那后来白雪公主又是怎么与小霍比特人们幸福快乐地生活在一块儿了呢?这里要提的是7个小霍比特人中,有一位博学的老者theWise,他曾在人类社会中生活了大半辈子,他曾任职于『跨种族文化研究协会』Cross-Racial Culture(CRC)。那段难忘的研究经历让他对Human的文化也是至关熟悉:ui

1 class CRC: public Human, public Hobbit {
2 public:
3     // ... other action ...    
4     virtual void hohobi() { hello(); }
5 }

能够看到,CRC其实就是一个适配器,更具体的说,是类适配器。(适配器模式有两种版本:类适配器对象适配器,下文会讲到)它使用多重继承对一个接口与另外一个接口进行匹配,见示例部分的说明。你们能够想一想现实生活中,咱们是否是还见过许多相似适配器的设计?让咱们来看看适配器模式的相关要点。spa

要点梳理

  • 目的分类
    • 类对象结构型模式
  • 范围准则
    • 对象(该模式处理对象间的关系,这些关系在运行时刻是能够变化的,更具动态性)
    • 类(该模式处理类和子类之间的关系,这些关系经过继承创建,是静态的,在编译时刻便肯定下来了)
  • 主要功能
    • 将一个类的接口转换成客户但愿的另一个接口。Adapter模式使得本来因为接口不兼容而不能一块儿工做的那些类能够一块儿工做
  • 适用状况
    • 咱们想使用一个已经存在的类,而它的接口不符合咱们的需求
    • 咱们想建立一个能够复用的类,该类能够与其余不相关的类或不可预见的类(即那些接口设计

      可能不必定兼容的类)协同工做
  • 参与部分
    • Target:定义Client使用的与特定领域相关的接口
    • Client:与符合Target接口的对象协同
    • Adaptee:定义一个已经存在的接口,这个接口须要适配
    • Adapter:对Adaptee的接口与Target接口进行适配
  • 协做过程
    •  ClientAdapter实例上调用一些操做。接着适配器调用Adaptee的操做实现这个请求
  • UML图

类适配器指针

对象适配器code

示例分析 - 跨越语言的障碍

当美丽的白雪公主遇到一个可爱的小霍比特人时,她向他打招呼:htm

1 Human theWhitePrincess = new Human();
2 Hobbit theLovely = new Hobbit();
3 theWhitePrincess.hello(); //你好!

可是小霍比特人理解不了。在他的世界里,hohobi()才是打招呼的方式。而Human是没有hohobi()的,因而白雪公主沟通陷入了尴尬的状态。好在theWise及时的来了:对象

1 Hobbit theWise = new CRC();
2 theWise.hohobi(); //你好!

因而白雪公主和其余小霍比特人经过theWise都能互相理解了。借用下面这个图咱们能够理解下:

跨种族文化研究协会就是为了实现种族之间文化交流沟通没有障碍而生。它在这个场景下,就起到了适配器的做用,经过将Hobbit人打招呼的接口hobbit()转化成Human打招呼的接口hello进行输出。

可是世界的创造者时の魔导士也注意到了这件事。他并不但愿之后的日子里,白雪公主都要在theWise的陪同下才能与其余人沟通,太不方便了对不对。因而他采用了童话世界里最常出现的谜之物:霍比特仙果:一个能吃了后能让人类得到理解霍比特人的神奇果实。从本质上来看,吃过果子后,属于新的类别:HumanPlus

1 class HumanPlus : public Human {
2 public:
3     // ... other action ...
4     virtual void hello() { _hobbitSprite->hohobi(); }
5 private:
6     Hobbit* _hobbitSprite;
7 }

它的最大特点是,本身维护了一个Hobbit类的指针。利用_hobbitSprite对象达到适配器的目的,这就是另外一种对象适配器的模式。让咱们来看图:

总之,白雪公主顺利地融入到小霍比特人的生活中。

特色总结

在此,咱们能够总结下类适配器对象适配器各自的特色:

  1. 类适配器用一个具体的Adapter类对Adaptee和Target进行匹配。但如此一来,类Adapter将不能匹配Adaptee类的全部子类了。
  2. 对于类适配器,Adapter类是Adaptee类的子类,所以能够重定义Adaptee类的部分行为。
  3. 对于类适配器,仅仅引入一个对象,并不须要额外的指针以间接获得adaptee
  4. 对象适配器则容许一个Adapter与多个Adaptee同时工做,它也能够一次给全部的Adaptee添加额外的功能。
  5. 对于对象适配器,重定义Adaptee的行为自己比较困难。

咱们须要注意的一些问题:

  1. 对Adaptee的接口与Target的接口进行匹配的工做量各个Adapter可能不同,主要取决于Target接口与Adaptee接口的类似程度。
  2. 当其余的类使用一个类时,若是所需的假定条件越少,这个类就更具可复用性。若是将接口匹配构建为一个类,就不须要假定对其余的类可见的是一个相同的接口。也就是说,接口匹配使得咱们能够将本身的类加入到一些现有的系统中去,而这些系统对这个类的接口可能会有所不一样。
  3. 使用适配器的一个潜在问题是,它们不对全部的客户都透明。被适配的对象再也不兼容Adaptee的接口,所以并非全部Adaptee对象能够被使用的。这种状况下,一个双向的适配器就颇有必要了。通常可使用多重继承来实现这一目的,尤为是两个类接口差别程度较大时。

写在最后

今天的笔记就到这里了,欢迎你们批评指正!若是以为能够的话,好文推荐一下,我会很是感谢的!

相关文章
相关标签/搜索