设计模式4 结构型模式
设计模式4 结构型模式
目录代理模式装饰器外观模式适配器模式
代理模式,美国,韩国代理购物
chunli@linux:~$catmain.cpp#include<iostream>usingnamespacestd;classItem//商品{public:Item(stringkind,boolfact){this->kind=kind;this->fact=fact;}stringgetKind(){returnkind;}boolgetFact(){returnfact;}private:stringkind;boolfact;};classShopping//抽象的购物方式{public:virtualvoidbuy(Item*it)=0;};classKoreaShopping:publicShopping//Korea购物{public:virtualvoidbuy(Item*it){cout<<"去Korea买了"<<it->getKind()<<endl;}};classUSAShopping:publicShopping//USA购物{public:virtualvoidbuy(Item*it){cout<<"去USA买了"<<it->getKind()<<endl;}};intmain(){Itemit_1("Nike鞋",true);if(it_1.getFact()==true)//辨别产品真假{cout<<"发现真货"<<endl;Shopping*koreaShopping=newKoreaShopping;koreaShopping->buy(&it_1);//代理cout<<"过安检"<<endl;}else{cout<<"假货,不要买"<<endl;}Itemit_2("英语证书",false);return0;}chunli@linux:~$g++main.cpp-Wall&&./a.out发现真货去Korea买了Nike鞋过安检chunli@linux:~$
代理模式,海外代理韩国与美国
chunli@linux:~$catmain.cpp#include<iostream>usingnamespacestd;classItem//商品{public:Item(stringkind,boolfact){this->kind=kind;this->fact=fact;}stringgetKind(){returnkind;}boolgetFact(){returnfact;}private:stringkind;boolfact;};classShopping//抽象的购物方式{public:virtualvoidbuy(Item*it)=0;};classKoreaShopping:publicShopping//Korea购物{public:virtualvoidbuy(Item*it){cout<<"去Korea买了"<<it->getKind()<<endl;}};classUSAShopping:publicShopping//USA购物{public:virtualvoidbuy(Item*it){cout<<"去USA买了"<<it->getKind()<<endl;}};classOverseaProxy:publicShopping{public:OverseaProxy(Shopping*shopping){this->shopping=shopping;}virtualvoidbuy(Item*it){//购买之前............if(it->getFact()==false){cout<<"发现假货,不要购买"<<endl;return;}//开始购买shopping->buy(it);//购买之后cout<<"通过安检,后买成功!"<<endl;}private:Shopping*shopping;};intmain(){Shopping*usaShopping=newUSAShopping;Shopping*overseaProxy=newOverseaProxy(usaShopping);Itemit1("英语证书",false);overseaProxy->buy(&it1);Itemit2("Dell服务器",true);overseaProxy->buy(&it2);return0;}chunli@linux:~$g++main.cpp-Wall&&./a.out发现假货,不要购买去USA买了Dell服务器通过安检,后买成功!chunli@linux:~$
看图:
subject(抽象主题角色):真实主题与代理主题的共同接口。
RealSubject(真实主题角色):定义了代理角色所代表的真实对象。
Proxy(代理主题角色): 含有对真实主题角色的引用,代理角色通常在
将客户端调用传递给真是主题对象之前或者之后执行某些操作,而不是单纯返
回真实的对象。
优点:
(1) 能够协调调用者和被调用者,在一定程度上降低了系统的耦合度。
(2) 客户端可以针对抽象主题角色进行编程,增加和更换代理类无须修改源
代码,符合开闭原则,系统具有较好的灵活性和可扩展性。
缺点:
(1) 代理实现较为复杂。
---------------------------------------------------------------------
装饰器:把手机裸机 装饰成有贴膜的手机
chunli@linux:~$catmain.cpp#include<iostream>usingnamespacestd;classPhone{public:virtualvoidshow()=0;};classiPhone:publicPhone{public:virtualvoidshow(){cout<<"秀出了iPhone"<<endl;}};classMi:publicPhone{public:virtualvoidshow(){cout<<"秀出了小米"<<endl;}};//抽象装饰器classDecorator:publicPhone{public:Decorator(Phone*phone){this->phone=phone;}virtualvoidshow()=0;protected:Phone*phone;//拥有一个手机的父类指针};//贴膜装饰器classMoDecorator:publicDecorator{public:MoDecorator(Phone*phone):Decorator(phone){}virtualvoidshow(){this->phone->show();this->mo();}voidmo(){cout<<"手机贴膜了"<<endl;}};intmain(){Phone*phone=newiPhone;//创建一个裸机phone->show();//裸机show()cout<<"---------------"<<endl;Phone*mophone=newMoDecorator(phone);mophone->show();return0;}chunli@linux:~$g++main.cpp-Wall&&./a.out秀出了iPhone---------------秀出了iPhone手机贴膜了chunli@linux:~$
装饰器,在贴膜的手机,加壳
chunli@linux:~$g++main.cpp-Wall&&./a.out秀出了iPhone---------------秀出了iPhone手机贴膜了---------------秀出了iPhone手机贴膜了手机加壳了chunli@linux:~$chunli@linux:~$catmain.cpp#include<iostream>usingnamespacestd;classPhone{public:virtualvoidshow()=0;};classiPhone:publicPhone{public:virtualvoidshow(){cout<<"秀出了iPhone"<<endl;}};classMi:publicPhone{public:virtualvoidshow(){cout<<"秀出了小米"<<endl;}};//抽象装饰器classDecorator:publicPhone{public:Decorator(Phone*phone){this->phone=phone;}virtualvoidshow()=0;protected:Phone*phone;//拥有一个手机的父类指针};//贴膜装饰器classMoDecorator:publicDecorator{public:MoDecorator(Phone*phone):Decorator(phone){}virtualvoidshow(){this->phone->show();this->mo();}voidmo(){cout<<"手机贴膜了"<<endl;}};//手机壳装饰器classShellDecorator:publicDecorator{public:ShellDecorator(Phone*phone):Decorator(phone){}virtualvoidshow(){this->phone->show();this->shell();}voidshell(){cout<<"手机加壳了"<<endl;}};intmain(){Phone*phone=newiPhone;//创建一个裸机phone->show();//裸机show()cout<<"---------------"<<endl;Phone*mophone=newMoDecorator(phone);mophone->show();cout<<"---------------"<<endl;Phone*shellPhone=newShellDecorator(mophone);shellPhone->show();return0;}chunli@linux:~$g++main.cpp-Wall&&./a.out秀出了iPhone---------------秀出了iPhone手机贴膜了---------------秀出了iPhone手机贴膜了手机加壳了chunli@linux:~$
看图
Component(抽象构件): 它是具体构件和抽象装饰类的共同父类,声
明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理
未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。
ConcreteComponent(具体构件): 它是抽象构件类的子类,用于定
义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额
外的职责(方法)。
Decorator(抽象装饰类): 它也是抽象构件类的子类,用于给具体构件
增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引
用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,
以达到装饰的目的。
ConcreteDecorator(具体装饰类):它是抽象装饰类的子类,负责向
构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在
抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。
4.2.3 装饰模式的优缺点
优点:
(1) 对于扩展一个对象的功能,装饰模式比继承更加灵活性,不会导致类的个数
急剧增加。
(2) 可以通过一种动态的方式来扩展一个对象的功能,从而实现不同的行为。
(3) 可以对一个对象进行多次装饰。
(4) 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构
件类和具体装饰类,原有类库代码无须改变,符合“开闭原则”。
缺点:
(1) 使用装饰模式进行系统设计时将产生很多小对象,大量小对象的产生势必会
占用更多的系统资源,影响程序的性能。
外观模式: 演示:为了调用AB方法,需要显式的调用AB
chunli@linux:~$catmain.cpp#include<iostream>usingnamespacestd;classSysA{public:voidoperationA(){cout<<"A........"<<endl;}};classSysB{public:voidoperationB(){cout<<"B........"<<endl;}};classSysC{public:voidoperationC(){cout<<"C........"<<endl;}};classSysD{public:voidoperationD(){cout<<"D........"<<endl;}};intmain(){SysAsysa;sysa.operationA();SysBsysb;sysb.operationB();return0;}chunli@linux:~$g++main.cpp&&./a.outA........B........chunli@linux:~$
现在只需要通过外观访问:打包组合起来
chunli@linux:~$catmain.cpp#include<iostream>usingnamespacestd;classSysA{public:voidoperationA(){cout<<"A........"<<endl;}};classSysB{public:voidoperationB(){cout<<"B........"<<endl;}};classSysC{public:voidoperationC(){cout<<"C........"<<endl;}};classSysD{public:voidoperationD(){cout<<"D........"<<endl;}};classFacade{public:voidmethodOne(){sysa.operationA();sysb.operationB();}voidmethodTwo(){sysc.operationC();sysd.operationD();}private:SysAsysa;SysBsysb;SysCsysc;SysDsysd;};intmain(){Facadeface;face.methodOne();return0;}chunli@linux:~$g++main.cpp&&./a.outA........B........chunli@linux:~$
适配器模式
手机充电需要使用5V电压,
创建一个适配器,将220V电压转换成5V
chunli@linux:~$catmain.cpp#include<iostream>usingnamespacestd;classV5{public:virtualvoiduseV5()=0;};//目前只有v220的类没有v5classV220{public:voiduseV220(){cout<<"使用了220v的电压"<<endl;}};//定义一个中间的适配器类classAdapter:publicV5{public:Adapter(V220*v220){this->v220=v220;}~Adapter(){if(this->v220!=NULL){deletethis->v220;}}virtualvoiduseV5(){v220->useV220();//调用需要另外的方法}private:V220*v220;};classiPhone{public:iPhone(V5*v5){this->v5=v5;}~iPhone(){if(this->v5!=NULL){deletethis->v5;}}//充电的方法voidcharge(){cout<<"iphone手机进行了充电"<<endl;v5->useV5();}private:V5*v5;};intmain(void){iPhone*phone=newiPhone(newAdapter(newV220));phone->charge();return0;}chunli@linux:~$g++main.cpp&&./a.outiphone手机进行了充电使用了220v的电压chunli@linux:~$
适配器模式中的角色和职责
Target(目标抽象类): 目标抽象类定义客户所需接口,可以是一个抽
象类或接口,也可以是具体类。
Adapter(适配器类):适配器可以调用另一个接口,作为一个转换
器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适
配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系。
Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在
的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使
用的业务方法,在某些情况下可能没有适配者类的源代码。
根据对象适配器模式结构图,在对象适配器中,客户端需要调用request(
方法,而适配者类Adaptee没有该方法,但是它所提供的specificRequest()方
法却是客户端所需要的。为了使客户端能够使用适配者类,需要提供一个包装
类Adapter,即适配器类。这个包装类包装了一个适配者的实例,从而将客户
端与适配者衔接起来,在适配器的request()方法中调用适配者的
specificRequest()方法。因为适配器类与适配者类是关联关系(也可称之为委
派关系),所以这种适配器模式称为对象适配器模式。
4.4.3 适配器模式优缺点
优点:
(1) 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者
类,无须修改原有结构。
(2) 增加了类的透明性和复用性, 将具体的业务实现过程封装在适配者类
中,对于客户端类而言是透明的,而且提高了适配者的复用性,同一个适配者
类可以在多个不同的系统中复用。
(3) 灵活性和扩展性都非常好 ,可以很方便地更换适配器,也可以在不修改
原有代码的基础上增加新的适配器类,完全符合“开闭原则”。
缺点:
适配器中置换适配者类的某些方法比较麻烦。
适应场景
(1) 系统需要使用一些现有的类,而这些类的接口(如方法名)不符合系
统的需要,甚至没有这些类的源代码。
(2) 想创建一个可以重复使用的类,用于与一些彼此之间没有太大关联的
一些类,包括一些可能在将来引进的类一起工作。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。