写在前面

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

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

在这个平行世界中,所有的Human通用语是中文,(为什么是中文!因为全世界都在学中国话。)包括白雪公主(你知道我是一定不会忠于原著的)。而霍比特人,我们假定他们用的是霍比特语。所以大家在表达“打招呼”的意思时,用的是完全不同的语言:

 class Human {
public:
// ... other action ...
virtual void hello() { cout << "你好!" << endl; }
} class Hobbit {
public:
// ... other action ...
virtual void hohobi() { cout << "HOhoBI*" << endl; }
}

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

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

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

要点梳理

  • 目的分类

    • 类对象结构型模式
  • 范围准则
    • 对象(该模式处理对象间的关系,这些关系在运行时刻是可以变化的,更具动态性)
    • 类(该模式处理类和子类之间的关系,这些关系通过继承建立,是静态的,在编译时刻便确定下来了)
  • 主要功能
    • 将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
  • 适用情况
    • 我们想使用一个已经存在的类,而它的接口不符合我们的需求
    • 我们想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口

      可能不一定兼容的类)协同工作

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

类适配器

对象适配器

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

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

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

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

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

于是白雪公主和其他小霍比特人通过theWise都能互相理解了。借用下面这个图我们可以理解下:

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

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

 class HumanPlus : public Human {
public:
// ... other action ...
virtual void hello() { _hobbitSprite->hohobi(); }
private:
Hobbit* _hobbitSprite;
}

它的最大特色是,自己维护了一个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对象可以被使用的。这种情况下,一个双向的适配器就很有必要了。一般可以使用多重继承来实现这一目的,尤其是两个类接口差异程度较大时。

写在最后

今天的笔记就到这里了,欢迎大家批评指正!如果觉得可以的话,好文推荐一下,我会非常感谢的!

[学习笔记]设计模式之Adapter的更多相关文章

  1. [学习笔记]设计模式之Chain of Responsibility

    为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 最近时间比较紧,所以发文的速度相对较慢了.但是看到园子里有很多朋友对设计模式感兴趣,我感觉很高兴,能够和大家一起学习这些知识. 之前的 ...

  2. [学习笔记]设计模式之Abstract Factory

    写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 在上篇笔记Builder设计模式中,时の魔导士祭出了自己的WorldCreator.尽管它因此能创造出一个有山有树有房子的世界,但是白 ...

  3. [学习笔记]设计模式之Builder

    写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 作为一个新入职的魔导士呢,哦不,是程序员,我以为并没有太多机会去设计项目的软件架构.但是,工作一段时间之后,自己渐渐意识到,哪怕是自己 ...

  4. [学习笔记]设计模式之Bridge

    写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 “魔镜啊魔镜,谁是这个世界上最美丽的人?”月光中,一个低沉的声音回荡在女王的卧室.“是美丽的白雪公主,她正和小霍比特人们幸福快乐地生活 ...

  5. [学习笔记]设计模式之Prototype

    写在前面 为方便读者,本文已添加至索引: 设计模式 学习笔记索引 在笔记Builder模式中,我们曾见到了最初用于创建平行世界的函数createWorld,并且它是Mage类的成员函数(毕竟是专属于魔 ...

  6. [学习笔记]设计模式之Command

    为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 在上篇Chain of Responsibility(职责链)模式笔记中,我们学习了一种行为型设计模式.今天,我们继续这一主题,来学习 ...

  7. [学习笔记]设计模式之Composite

    为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 在Composite(组合)模式中,用户可以使用多个简单的组件以形成较大的组件,而这些组件还可能进一步组合成更大的.它重要的特性是能够 ...

  8. [学习笔记]设计模式之Proxy

    为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 “魔镜啊魔镜,谁是这个世界上最美丽的人?” 每到晚上,女王都会问魔镜相同的问题(见Decorator模式).这是她还曾身为女巫时留下的 ...

  9. [学习笔记]设计模式之Flyweight

    为方便读者,本文已添加至索引: 设计模式 学习笔记索引 写在前面 Flyweight(享元)模式运用共享技术,可以有效地支持大量细粒度的对象.今天我们会去参观小霍比特人们的酿酒工坊……等等,不是享元模 ...

随机推荐

  1. 【技术贴】三星Note8 N5100实用教程,关闭相机快门声,增加浏览器退出按钮。

    需要root 增加快门声按钮: 在\system\csc\目录下,有个others.xml的手机功能定制文件,用root explorer之类可以修改系统文件权限的文本修改工具编辑它,在文件最末添加这 ...

  2. win7下登陆中国银行网上银行IE浏览器版本过高问题解决

    2013-11-23 2013-11-23登录中国银行出现以下提示. 操作系统为windows7 64位旗舰版,搜狗浏览器版本为4.1.1.7598.想不到突然出现如下提示.打电话去问,告知使用IE7 ...

  3. vs2010 dll生成,使用问题[good]

    VS2010 动态库开发——第一章 演练:创建和使用动态链接库 (C++) 转载自[http://www.cnblogs.com/sdlypyzq/archive/2012/01/17/2324215 ...

  4. Uncompressing Linux___ done, booting the kernel_tekkamanninja-ChinaUnix博客

    今天用主线Linux内核移植到MINI6410,主线内核2.6.37.1基本已经支持了MINI6410的板子,所以移植到能够启动起来的阶段很简单,但是在移植的时候还是出现了一个比较常见的问题: MIN ...

  5. bzoj1264

    表面上看这是一道LCS问题 LCS问题O(n2)的复杂度已经很优秀了 而这道题需要O(nlogn)以下的复杂度才能AC 所以我们要找经典问题的特殊性 特殊就在这两个串中,每个数字都是恰好出现5次 不难 ...

  6. pcDuino 刷系统-LiveSuit

    准备: pcduino : 点此购买 支持HDMI的显示器:点此购买  或参考无显示器刷机与使用.至少1张4G microSD卡,如果内存卡不大,可以用内存卡刷内核,用u盘刷系统   LiveSuit ...

  7. 【Jade】

    Jade 模板引擎使用 Jade - 模板引擎 Jade - Template Engine

  8. 模式串匹配KMP详解

    关于KMP模式串匹配网上蛮多的. 对于KMP有自己理解所以写下来希望能够对你们的学习有帮助. 之前暑假的时候学过,然后好长时间没用发现又忘了,现在再看看发现有了新的理解. ============== ...

  9. The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.

    The server is temporarily unable to service your request due to maintenance downtime or capacity pro ...

  10. (转载)C++中, 构造函数和析构函数能不能被显示调用?

    (转载)http://blog.csdn.net/zhangxinrun/article/details/6056321 代码: view plaincopy to clipboardprint?#i ...