适配器模式(Adapter)

来源:互联网 发布:mysql 集群 phxsql 编辑:程序博客网 时间:2024/06/03 19:01

Adapter模式

将一个类的接口转换成客户希望的另外一个接口。Adapter模式使原本由于接口不兼容而不能一起工作的类可以一起工作。[设计模式解析]

即:之前的接口不合适,但是功能是正确的,为了使用这个功能,我们需要为其创建一个新的接口。

这里写图片描述
通过写一个类,可以将原本不匹配的接口转换成期望的接口。
例一:
火鸡转换器
这里写图片描述

策略模式中的鸭子:

class Duck{public:    virtual void quack() = 0;    virtual void fly() = 0;};

绿头鸭:

class MallardDuck: public Duck{public:    void quack(){        cout << “Quack” << endl;}    void fly(){        cout << “I’m flying…” << endl;    }};

“街头顽禽”

class Turkey{public:    virtual void gobble() = 0;    virtual void fly() = 0;};
class WildTurkey : public Turkey{public:    void gobble(){        cout << “Gobble gobble…” << endl;    }void fly(){    cout << “I’m flying a short distanc” << endl;    }};

火鸡适配器:

class TurkeyAdapter: public Duck{Turkey *turkey;public:    TurkeyAdapter(Turkey * turkey){        this->turkey = turkey;    }    void quack() {        turkey->gobble();    }    void fly(){        for(int i=0; i<5; ++i)            turkey->fly();      // 火鸡飞五次达到鸭子飞行距离    }};
int main(){    Duck * mallarDuck = new MallardDuck();    // mallarDuck->fly();    // mallarDuck->quack();    WildTurkey * turkey = new WildTurkey();    // turkey->gobble();    // turkey->fly();    Duck * fakeDuck = new TurkeyAdapter(turkey);    fakeDuck->quack();    fakeDuck->fly();    return 0;}

火鸡与鸭子并非同类,客户(main函数)想通过调用quak和fly方法也能让火鸡叫和飞。火鸡是被适配者,于是需要一个中间类—-适配器,修饰火鸡的叫(gobble)与飞(fly)。

火鸡适配器类TurkeyAdapter,继承自Duck类,构造函数中,传入火鸡,在quack函数中调用火鸡的gobble,fly函数中调用火鸡的fly。

这样,通过中间的火鸡适配器对目标”接口”—-gobble和fly进行转换, 客户就可以继续使用Duck的quack和fly方法。让火鸡叫的像鸭子,飞的像鸭子。

客户使用适配器过程如下:
1). 客户通过目标接口调用适配器的方法,对适配器发出请求。

Duck * fakeDuck = new TurkeyAdapter(turkey);fakeDuck->quack();               //  调用Duck的quack && flyfakeDuck->fly();

2). 适配器使用被适配者接口把请求转换成被适配者的一个或者多个调用接口。

void quack() {               // 适配器中将对quack的调用转换为火鸡的gobble    turkey->gobble();}

3). 客户接收到调用的结果,但并未察觉这一切是适配器在起转换作用。

Duck * fakeDuck = new TurkeyAdapter(turkey);fakeDuck->quack();

适配器的工作量和目标接口的大小成正比,如果不使用适配器,将会花很多力气来修改turkey中的代码。
适配器 v.s. 装饰
装饰 –> 相同的接口,在组合中添加新的功能
适配器 –> 将不符合的目标接口转换成期望的接口。

对象适配器:
这里写图片描述

将用户与接口绑定起来,main —- Duck。 使用组合的方式,以修改的接口(鸭子适配器)包装被适配者(火鸡)。被适配者的任何子类,都可以和适配器工作。也可以在适配器中加入新的内容,只要遵循目标接口就行。

类适配器:
这里写图片描述
适合在多重继承语言中。

如果要让一个适配器包装多个被适配者,就需要外观模式(Façade Pattern)。外观模式可以简化接口,隐藏众多复杂的接口。

比如:电脑上的一键装机。。。可能不太合适。。。如果没有外观模式,就需要装系统,重启,装驱动,装常用软件等等,有了意见装机之后,只要点下鼠标,所有工作一次性完成。
书上面是:电影院一系列的开机工作(将灯光调暗,放下屏幕,打开投影机,打开DVD机。。。播放。。。),用一个按钮完成。

除此之外,外观模式还可以将客户从组件的子系统中解耦。通过定义一个高层的接口,在不修改系统功能的同时,让子系统更加容易使用。

如果在简化接口的同时,增加新的功能 –> Facade模式变体。
例二
现有点、线、正方形的三个类,这三个类中均有 自我显示 和 自我擦除 的功能。
但是希望客户认为只有形状,这样客户就可以相同的方式处理所有的对象。

这会让您想到抽象和多态。虽然有不同的对象,但是与他们的交互式通用的。
Adapter模式
图片来源: http://blog.csdn.net/rj03hou/article/details/2416407
表示现在有个类不知道叫啥名字,假设是上图中的Class,那么它依赖于Shape这个基类。即,把Shape通过参数的形式传递给Class这个类。

现在呢,由于需求增加了,客户想绘制圆,刚好得知公司有人之前写过圆的绘制擦除操作这样一个类:XXCicle,但是这个类的函数名,函数参数与Shape的并不相同(Shape中的函数为display()、 undisplay())。于是,我们需要将其接口统一(与Shape类的函数名相同)。
Adapter模式

Adapter模式可以将一个已有的接口转换成另一个接口,原先的功能合适,但是原有的接口的名称或者参数和我们想要的并不一致,所以,将接口修改,如:修改接口的名称,增减接口的参数。

意图 使控制范围之外的一个原有对象与某个接口匹配(圆这个类是该系统原先没有的,但是其他系统中实现过这个绘制圆的类,想要用它但是接口不匹配) 问题 数据和行为均正确,但是与抽象类的接口不符合 参与者与协作者 Adapter(Circle)改变了Adaptee(XXCircle)的接口,这样Shape就可以使用Circle了 效果 Adapter模式使原有对象能够适应新的类结构,不受接口的限制 实现 将原有类包含在另一个类中。让包含的类与需要的接口匹配,调用被包含类的方法。

在现实中,可能XXCircle类中只有一部分的功能可以使用,也没关系,将可以使用的那部的接口修改一下,然后缺少的功能在Circle类中进行实现—-(Adapter模式变体)。

Adapter模式类型:

  1. 对象Adapter模式:一个对象(Circle对象—-适配器)包含另一个对象(XXCircle对象—-被适配者)

    class Shape{virtual void  display()=0;};class XXCircle{public:XXCircle(){    cout << "XXCircle Constructor: XXCircle()\n";}void displayIt() { cout <<"displayIt()\n"; }};class Circle : private Shape{private:    XXCircle *myXXCircle;public:    Circle(){        myXXCircle = new XXCircle();    }    void display(){        myXXCircle->displayIt();    }};
  2. 类Adapter模式 :多重继承。
#include <iostream>using namespace std;// "ITarget"class ITarget{public:    virtual void Request() = 0;};// "Adaptee"被适配者class Adaptee{public :    void SpecificRequest()    {        cout << "Called SpecificRequest()" ;    }};// "Adapter" 适配器class Adapter :  Adaptee, public ITarget{public :    void Request()    {        this->SpecificRequest();    }};// Client testint main(){    ITarget *t = new Adapter();    t->Request();    return 0;}

依赖关系

Interfaces may be incompatible but the inner functionality should suit the need. The Adapter design pattern allows otherwise incompatible classes to work together by converting the interface of one class into an interface expected by the clients. [Adapter pattern]

接口可能不兼容,但是内部的功能能应该是适合所需。Adapter设计模式通过把接口转换(converting)成客户(Clients)期待的接口,达到 允许不兼容的类协调工作的目的。

对象Adapter模式:
对象Adapter模式
the adapter contains an instance of the class it wraps. In this situation, the adapter makes calls to the instance of the wrapped object.
包含一个它包裹的类的实例。适配器调用它包裹的实例。
类Adapter模式:
类
this type of adapter uses multiple polymorphic interfaces implementing or inheriting both the interface that is expected and the interface that is pre-existing. It is typical for the expected interface to be created as a pure interface class, especially in languages such as Java (before jdk 1.8) that do not support multiple inheritance of classes.
多个多态接口实现 / 继承自接口既有需要的接口又有预先存在的接口。 典型的它期待的接口是一个纯的接口类,如上面的 ITarget 类。

0 0
原创粉丝点击