Modem:Adapter模式与Bridge模式

来源:互联网 发布:js设置disable 编辑:程序博客网 时间:2024/05/22 05:16

</pre>本例取自《敏捷软件开发》第25章,使用C++实现<p></p><p></p><p>1.背景</p><p>    <img src="" alt="" /></p><p>         Modem类有四个接口,Dial、HandUp、Send、Receive,客户使用Modem,有三种实际的Modem与之对应</p><p></p><p>代码</p><p></p><pre code_snippet_id="475013" snippet_file_name="blog_20140925_2_2898509" name="code" class="cpp">#ifndef MODEM_H_#define MODEM_H_#include <string>#include <iostream>using namespace std;class Modem{public:virtual ~Modem(){}virtual void dial()=0;virtual void hangUp()=0;virtual void send()=0;virtual void receive()=0;};class HayesModem: public Modem{public:void dial(){cout<<"HayesModem dial!"<<endl;}void hangUp(){cout<<"HayesModem hangUp!"<<endl;}void send(){cout<<"HayesModem send!"<<endl;}void receive(){cout<<"HayesModem receive!"<<endl;}};class USRoboticsModem:public Modem{public:void dial(){cout<<"USRoboticsModem dial!"<<endl;}void hangUp(){cout<<"USRoboticsModem hangUp!"<<endl;}void send(){cout<<"USRoboticsModem send!"<<endl;}void receive(){cout<<"USRoboticsModem receive!"<<endl;}};#endif /* MODEM_H_ */

#include "Modem.h"void modem(){Modem& m1 = *(new HayesModem());m1.dial();m1.send();m1.receive();m1.hangUp();}

运行结果

HayesModem dial!
HayesModem send!
HayesModem receive!
HayesModem hangUp!

2.变化一

     有一种新的Modem加入,不需要拨号(没有Dial与HandUp的接口),对于该需求,理想的实现方式,是使用接口隔离原则(ISP)的思想,将四个接口分离为两个接口类(Dialer和Modem),使用DedicatedModem的客户不需要看到dial和hangUp接口

     也即,用户代码,如果给的是一个DedicatedModem的对象,他们的代码也是可以执行的。(原有dialModem用户的代码,如果给的是一个DedicatedModem的引用,而不是DialModem的引用,他们的代码是不用修改的,可能是为了升级吧)

class Dialler{public:virtual ~Dialler(){}virtual void dial()=0;virtual void hangUp()=0;};class Modem{public:virtual ~Modem(){}virtual void send()=0;virtual void receive()=0;};class HayesModem: public Modem, public Dialler{public:void dial(){cout<<"HayesModem dial!"<<endl;}void hangUp(){cout<<"HayesModem hangUp!"<<endl;}void send(){cout<<"HayesModem send!"<<endl;}void receive(){cout<<"HayesModem receive!"<<endl;}};class USRoboticsModem:public Modem, Dialler{public:void dial(){cout<<"USRoboticsModem dial!"<<endl;}void hangUp(){cout<<"USRoboticsModem hangUp!"<<endl;}void send(){cout<<"USRoboticsModem send!"<<endl;}void receive(){cout<<"USRoboticsModem receive!"<<endl;}};class DedicatedModem:public Modem{public:void send(){cout<<"DedicatedModem send!"<<endl;}void receive(){cout<<"DedicatedModem receive!"<<endl;}};

void modem(){HayesModem modem;DedicatedModem dModem;/*---------模拟客户代码------------*/Modem& m1 = modem;Dialler& d1 = modem;d1.dial();m1.send();m1.receive();d1.hangUp();Modem& m2 = dModem;m2.send();m2.receive();}

运行结果:

HayesModem dial!
HayesModem send!
HayesModem receive!
HayesModem hangUp!
DedicatedModem send!
DedicatedModem receive!


上述代码的问题在于,需要修改原有客户的代码(原有客户只是用Modem&,现在需要使用Modem&和Dialler&,当然,这个是在不让客户看到HayesModem和DedicatedModem类型的前提下的)


3.使用Adapt来解决

    引入一个Adapt来匹配DedicatedModem(两个接口)和Modem(四个接口),Adapt继承Modem(目标接口),并持有一个DedicatedModem的引用(还可以使用继承)

由其进行接口翻译,如果是send和receive,则委托给DedicatedModem,如果是dial和hangUp,则实现一个Fake的。

    这样,原有代码就不需要进行修改(使用拨号Modem的用户还是使用Modem的引用,新的使用DedicatedModem的用户,只是用send和receive接口)


class Modem{public:virtual ~Modem(){}virtual void dial()=0;virtual void hangUp()=0;virtual void send()=0;virtual void receive()=0;};class HayesModem: public Modem{public:void dial(){cout<<"HayesModem dial!"<<endl;}void hangUp(){cout<<"HayesModem hangUp!"<<endl;}void send(){cout<<"HayesModem send!"<<endl;}void receive(){cout<<"HayesModem receive!"<<endl;}};class USRoboticsModem:public Modem{public:void dial(){cout<<"USRoboticsModem dial!"<<endl;}void hangUp(){cout<<"USRoboticsModem hangUp!"<<endl;}void send(){cout<<"USRoboticsModem send!"<<endl;}void receive(){cout<<"USRoboticsModem receive!"<<endl;}};class DedicatedModem{public:void send(){cout<<"DedicatedModem send!"<<endl;}void receive(){cout<<"DedicatedModem receive!"<<endl;}};class DedicatedModemAdapter:public Modem{public:DedicatedModemAdapter(DedicatedModem& arg):modem(arg){}void dial(){cout<<"Fake dial!"<<endl;}void hangUp(){cout<<"Fake hangUp!"<<endl;}void send(){modem.send();}void receive(){modem.receive();}private:DedicatedModem& modem;};
void modem(){HayesModem modem;DedicatedModem dModem;DedicatedModemAdapter adapter(dModem);/*---------模拟客户代码------------*/Modem& m1 = modem;m1.dial();m1.send();m1.receive();m1.hangUp();DedicatedModem& m2 = dModem;m2.send();m2.receive();}
运行结果:

HayesModem dial!
HayesModem send!
HayesModem receive!
HayesModem hangUp!
DedicatedModem send!
DedicatedModem receive!


【为什么要引入Adapt?本来,如果直接定义一个DedicatedModem,其与Modem之间没有关联,对于原有使用dialmodem的用户和使用DedicatedModem的用户都没有影响】

原因在于,在引入DedicatedModem需求的时候的一个特殊的约定,就是“用户代码,如果给的是一个DedicatedModem的对象,他们的代码也是可以执行的”


比如将用户代码,修改为以下的样子,原有用户使用的引用m1已经从一个dialModem的对象变成了一个Adapter的对象,代码依旧要可以能够执行,所以说Adapte的引入,在这个例子中,更多的是为了兼容原有代码的需要。

void modem(){HayesModem modem;DedicatedModem dModem;DedicatedModemAdapter adapter(dModem);/*---------模拟客户代码------------*/Modem& m1 = adapter;m1.dial();m1.send();m1.receive();m1.hangUp();DedicatedModem& m2 = dModem;m2.send();m2.receive();}

执行结果:

Fake dial!
DedicatedModem send!
DedicatedModem receive!
Fake hangUp!
DedicatedModem send!
DedicatedModem receive!


4.使用Bridge模式来解决

    在建模的时候,可以将Modem作为一个抽象的类,然后派生出DialModem和DedicatedModem,然后这两个类分别可以有多个品牌的Modem来实现,但是这样的话,对于这种自由度不是很稳定(会扩展、会变化)的场景,用不了多久,就会派生出大量的类。

     Bridge就是将这些自由度(也可以做为变化方向)先进行打散,分为dial、hangup、send、receive四个自由度,每个自由度单独由一个Impler实现,Impler又通过接口委托给真实的Modem厂家来实现。然后ModemConnectionController又将这些变化方向“桥接”起来,组合成一个整体

代码

class Modem{public:virtual ~Modem(){}virtual void dial()=0;virtual void hangUp()=0;virtual void send()=0;virtual void receive()=0;};class DedicatedModem{public:virtual ~DedicatedModem(){}virtual void send()=0;virtual void receive()=0;};class ModemImplementation{public:virtual ~ModemImplementation(){}virtual void dial()=0;virtual void hangUp()=0;virtual void send()=0;virtual void receive()=0;};class HayesModem: public ModemImplementation{public:void dial(){cout<<"HayesModem dial!"<<endl;}void hangUp(){cout<<"HayesModem hangUp!"<<endl;}void send(){cout<<"HayesModem send!"<<endl;}void receive(){cout<<"HayesModem receive!"<<endl;}};class USRoboticsModem:public ModemImplementation{public:void dial(){cout<<"USRoboticsModem dial!"<<endl;}void hangUp(){cout<<"USRoboticsModem hangUp!"<<endl;}void send(){cout<<"USRoboticsModem send!"<<endl;}void receive(){cout<<"USRoboticsModem receive!"<<endl;}};class ModemConnectionController:public Modem, public DedicatedModem{public:ModemConnectionController(ModemImplementation& arg):impl(arg){}protected:void dialImp(){impl.dial();}void hangUpImp(){impl.hangUp();}void sendImp(){impl.send();}void receiveImp(){impl.receive();}private:ModemImplementation& impl;};class DedModemController:public ModemConnectionController{public:DedModemController(ModemImplementation& arg):ModemConnectionController(arg){}void dial(){cout<<"Fake dial!"<<endl;}void hangUp(){cout<<"Fake hangUp!"<<endl;}void send(){ModemConnectionController::sendImp();}void receive(){ModemConnectionController::receiveImp();}};class DialModemController:public ModemConnectionController{public:DialModemController(ModemImplementation& arg):ModemConnectionController(arg){}void dial(){ModemConnectionController::dialImp();}void hangUp(){ModemConnectionController::hangUpImp();}void send(){ModemConnectionController::sendImp();}void receive(){ModemConnectionController::receiveImp();}};

void modem(){HayesModem modem;DialModemController dialController(modem);DedModemController dedController(modem);/*---------模拟客户代码------------*/Modem& m1 = dialController;m1.dial();m1.send();m1.receive();m1.hangUp();DedicatedModem& m2 = dedController;m2.send();m2.receive();}

执行结果:

HayesModem dial!
HayesModem send!
HayesModem receive!
HayesModem hangUp!
HayesModem send!
HayesModem receive!


这种实现,就会有很多的好处,首次它分离了连接策略和硬件实现。ModemConnectController的每个派生类代表了一个新的连接策略。在这个策略的实现中可以使用sendImp、receiveImp、dialImp和hangImp中的一个或者多个。新imp方法的增加不会影响到使用者

可以直接替换Modem的实现,不用考虑Modem是Dedi还是Dial这个变化方向

void modem(){HayesModem modem;USRoboticsModem modem2;DialModemController dialController(modem);DedModemController dedController(modem2);/*---------模拟客户代码------------*/Modem& m1 = dialController;m1.dial();m1.send();m1.receive();m1.hangUp();DedicatedModem& m2 = dedController;m2.send();m2.receive();}

实现结果:

HayesModem dial!
HayesModem send!
HayesModem receive!
HayesModem hangUp!
USRoboticsModem send!
USRoboticsModem receive!


5.总结

   使用Adapter模式的解决方案是简单和直接的。它让所有的依赖关系都指向正确的方向,并且实现起来非常简单。Bridge模式稍稍有些复杂,建议开始时不要使用bridge模式,知道你明显可以看出需要完全分离出连接策略和通信策略并且需要增加新的连接策略时,才使用这种方法。


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 论文没过拿不到毕业证怎么办 大学论文不过拿不到毕业证怎么办 转店被黑中介骗了钱怎么办? 被星外转铺骗了怎么办 店铺转了后悔了怎么办 商铺转让不出去怎么办? 和包券密码丢失怎么办 天猫购物卷兑换不了怎么办 淘宝新店每天只有几个访客怎么办 注册淘宝企业店铺需要审核怎么办 淘宝店铺被投诉知识产权怎么办 一般违规扣48分怎么办 金税盘处于报税期不能开票怎么办 小规模税率开错了怎么办 我是代购卖家被买家投诉偷税怎么办 天猫盒子内存不够怎么办 天猫品牌申请不通过怎么办 天猫商家发货发个空包裹怎么办 无限流量怎么办没有4g 海外直邮身份证过期了怎么办 买车的人不过户怎么办 天猫精灵球泡离线怎么办 花呗被骗了2万怎么办 天猫公司变更地址发票怎么办 支付宝自助解限怎么办 支付宝16岁限额怎么办 支付宝提不了现怎么办 支付宝余额受限需要身份证怎么办 微信被骗了6000怎么办 被代运营骗了该怎么办 淘宝店铺过节放假无人打理怎么办 淘宝店太久没打理出现未开店怎么办 淘宝店关了售后怎么办 发货运单号发错了怎么办 天猫积分为零怎么办 山东聊城小型车脱审一年怎么办? 廉租房如果夫妻离婚怎么办 淘宝客服不给退货怎么办 天猫客服打字慢怎么办 京东买的kindle坏了怎么办 欧巴怎么办韩语怎么写