设计模式4 结构型模式
目录 代理模式 装饰器 外观模式 适配器模式
代理模式,美国,韩国代理购物
chunli@linux:~$ cat main.cpp #include<iostream> using namespace std; class Item //商品 { public: Item(string kind ,bool fact) { this->kind = kind; this->fact = fact; } string getKind() { return kind; } bool getFact() { return fact; } private: string kind ; bool fact; }; class Shopping //抽象的购物方式 { public: virtual void buy(Item *it) =0; }; class KoreaShopping:public Shopping //Korea购物 { public: virtual void buy(Item *it) { cout << "去Korea 买了" << it->getKind() << endl; } }; class USAShopping:public Shopping //USA购物 { public: virtual void buy(Item *it) { cout << "去USA 买了" << it->getKind() << endl; } }; int main() { Item it_1("Nike鞋",true); if(it_1.getFact() == true) //辨别产品真假 { cout << "发现真货" << endl; Shopping *koreaShopping = new KoreaShopping; koreaShopping->buy(&it_1);//代理 cout << "过安检" << endl; } else { cout << "假货,不要买" << endl; } Item it_2("英语证书",false); return 0; } chunli@linux:~$ g++ main.cpp -Wall && ./a.out 发现真货 去Korea 买了Nike鞋 过安检 chunli@linux:~$
代理模式,海外代理韩国与美国
chunli@linux:~$ cat main.cpp #include<iostream> using namespace std; class Item //商品 { public: Item(string kind ,bool fact) { this->kind = kind; this->fact = fact; } string getKind() { return kind; } bool getFact() { return fact; } private: string kind ; bool fact; }; class Shopping //抽象的购物方式 { public: virtual void buy(Item *it) =0; }; class KoreaShopping:public Shopping //Korea购物 { public: virtual void buy(Item *it) { cout << "去Korea 买了" << it->getKind() << endl; } }; class USAShopping:public Shopping //USA购物 { public: virtual void buy(Item *it) { cout << "去USA 买了" << it->getKind() << endl; } }; class OverseaProxy:public Shopping { public: OverseaProxy(Shopping *shopping) { this->shopping = shopping; } virtual void buy(Item *it) { //购买之前............ if(it->getFact() == false) { cout << "发现假货,不要购买" << endl; return ; } //开始购买 shopping->buy(it); //购买之后 cout << "通过安检,后买成功!" << endl; } private: Shopping *shopping; }; int main() { Shopping *usaShopping = new USAShopping; Shopping *overseaProxy = new OverseaProxy(usaShopping); Item it1("英语证书",false); overseaProxy->buy(&it1); Item it2("Dell 服务器",true); overseaProxy->buy(&it2); return 0; } chunli@linux:~$ g++ main.cpp -Wall && ./a.out 发现假货,不要购买 去USA 买了Dell 服务器 通过安检,后买成功! chunli@linux:~$
看图:
subject(抽象主题角色):真实主题与代理主题的共同接口。
RealSubject(真实主题角色):定义了代理角色所代表的真实对象。
Proxy(代理主题角色): 含有对真实主题角色的引用,代理角色通常在
将客户端调用传递给真是主题对象之前或者之后执行某些操作,而不是单纯返
回真实的对象。
优点:
(1) 能够协调调用者和被调用者,在一定程度上降低了系统的耦合度。
(2) 客户端可以针对抽象主题角色进行编程,增加和更换代理类无须修改源
代码,符合开闭原则,系统具有较好的灵活性和可扩展性。
缺点:
(1) 代理实现较为复杂。
---------------------------------------------------------------------
装饰器:把手机裸机 装饰成有贴膜的手机
chunli@linux:~$ cat main.cpp #include<iostream> using namespace std; class Phone { public: virtual void show() = 0; }; class iPhone:public Phone { public: virtual void show() { cout << "秀出了iPhone"<< endl; } }; class Mi:public Phone { public: virtual void show() { cout << "秀出了 小米"<< endl; } }; //抽象装饰器 class Decorator:public Phone { public: Decorator(Phone *phone) { this->phone = phone; } virtual void show() = 0; protected: Phone *phone;//拥有一个手机的父类指针 }; //贴膜装饰器 class MoDecorator:public Decorator { public: MoDecorator(Phone *phone):Decorator(phone) { } virtual void show() { this->phone->show(); this->mo(); } void mo() { cout << "手机 贴膜了 " << endl; } }; int main() { Phone *phone = new iPhone; //创建一个裸机 phone->show();//裸机 show() cout << "---------------" <<endl; Phone *mophone = new MoDecorator(phone); mophone->show(); return 0; } 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:~$ cat main.cpp #include<iostream> using namespace std; class Phone { public: virtual void show() = 0; }; class iPhone:public Phone { public: virtual void show() { cout << "秀出了iPhone"<< endl; } }; class Mi:public Phone { public: virtual void show() { cout << "秀出了 小米"<< endl; } }; //抽象装饰器 class Decorator:public Phone { public: Decorator(Phone *phone) { this->phone = phone; } virtual void show() = 0; protected: Phone *phone;//拥有一个手机的父类指针 }; //贴膜装饰器 class MoDecorator:public Decorator { public: MoDecorator(Phone *phone):Decorator(phone) { } virtual void show() { this->phone->show(); this->mo(); } void mo() { cout << "手机 贴膜了 " << endl; } }; //手机壳 装饰器 class ShellDecorator:public Decorator { public: ShellDecorator(Phone *phone):Decorator(phone) { } virtual void show() { this->phone->show(); this->shell(); } void shell() { cout << "手机 加壳了 " << endl; } }; int main() { Phone *phone = new iPhone; //创建一个裸机 phone->show();//裸机 show() cout << "---------------" <<endl; Phone *mophone = new MoDecorator(phone); mophone->show(); cout << "---------------" <<endl; Phone *shellPhone = new ShellDecorator(mophone); shellPhone->show(); return 0; } 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:~$ cat main.cpp #include<iostream> using namespace std; class SysA { public: void operationA() { cout << "A........" << endl; } }; class SysB { public: void operationB() { cout << "B........" << endl; } }; class SysC { public: void operationC() { cout << "C........" << endl; } }; class SysD { public: void operationD() { cout << "D........" << endl; } }; int main() { SysA sysa; sysa.operationA(); SysB sysb; sysb.operationB(); return 0; } chunli@linux:~$ g++ main.cpp && ./a.out A........ B........ chunli@linux:~$
现在只需要通过外观访问:打包组合起来
chunli@linux:~$ cat main.cpp #include<iostream> using namespace std; class SysA { public: void operationA() { cout << "A........" << endl; } }; class SysB { public: void operationB() { cout << "B........" << endl; } }; class SysC { public: void operationC() { cout << "C........" << endl; } }; class SysD { public: void operationD() { cout << "D........" << endl; } }; class Facade { public: void methodOne() { sysa.operationA(); sysb.operationB(); } void methodTwo() { sysc.operationC(); sysd.operationD(); } private: SysA sysa; SysB sysb; SysC sysc; SysD sysd; }; int main() { Facade face; face.methodOne(); return 0; } chunli@linux:~$ g++ main.cpp && ./a.out A........ B........ chunli@linux:~$
适配器模式
手机充电需要使用5V电压,
创建一个适配器,将220V电压转换成5V
chunli@linux:~$ cat main.cpp #include <iostream> using namespace std; class V5 { public: virtual void useV5() = 0; }; //目前只有v220的类 没有v5 class V220 { public: void useV220() { cout << "使用了220v的电压" << endl; } }; //定义一个中间的适配器类 class Adapter :public V5 { public: Adapter(V220 * v220) { this->v220 = v220; } ~Adapter() { if (this->v220 != NULL) { delete this->v220; } } virtual void useV5() { v220->useV220(); //调用需要另外的方法 } private: V220 *v220; }; class iPhone { public: iPhone(V5 *v5) { this->v5 = v5; } ~iPhone() { if (this->v5 != NULL) { delete this->v5; } } //充电的方法 void charge() { cout << "iphone手机进行了充电" << endl; v5->useV5(); } private: V5*v5; }; int main(void) { iPhone *phone = new iPhone(new Adapter(new V220)); phone->charge(); return 0; } chunli@linux:~$ g++ main.cpp && ./a.out iphone手机进行了充电 使用了220v的电压 chunli@linux:~$
适配器模式中的角色和职责
Target(目标抽象类): 目标抽象类定义客户所需接口,可以是一个抽
象类或接口,也可以是具体类。
Adapter(适配器类):适配器可以调用另一个接口,作为一个转换
器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适
配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系。
Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在
的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使
用的业务方法,在某些情况下可能没有适配者类的源代码。
根据对象适配器模式结构图,在对象适配器中,客户端需要调用request(
方法,而适配者类Adaptee没有该方法,但是它所提供的specificRequest()方
法却是客户端所需要的。为了使客户端能够使用适配者类,需要提供一个包装
类Adapter,即适配器类。这个包装类包装了一个适配者的实例,从而将客户
端与适配者衔接起来,在适配器的request()方法中调用适配者的
specificRequest()方法。因为适配器类与适配者类是关联关系(也可称之为委
派关系),所以这种适配器模式称为对象适配器模式。
4.4.3 适配器模式优缺点
优点:
(1) 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者
类,无须修改原有结构。
(2) 增加了类的透明性和复用性, 将具体的业务实现过程封装在适配者类
中,对于客户端类而言是透明的,而且提高了适配者的复用性,同一个适配者
类可以在多个不同的系统中复用。
(3) 灵活性和扩展性都非常好 ,可以很方便地更换适配器,也可以在不修改
原有代码的基础上增加新的适配器类,完全符合“开闭原则”。
缺点:
适配器中置换适配者类的某些方法比较麻烦。
适应场景
(1) 系统需要使用一些现有的类,而这些类的接口(如方法名)不符合系
统的需要,甚至没有这些类的源代码。
(2) 想创建一个可以重复使用的类,用于与一些彼此之间没有太大关联的
一些类,包括一些可能在将来引进的类一起工作。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。