您好,登錄后才能下訂單哦!
設計模式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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。