解決的問題:
我們在裝飾新家的時候買了幾幅抽象畫,買回來之后發(fā)現(xiàn)有些加上色彩艷麗的邊框更適合我們,而有的加上玻璃罩之后更能符合我們的使用。那我們來怎么解決這個問題呢?他需要動態(tài)的給別的對象增加額外的職責(zé),這就是裝飾者模式的目的。
我們可以通過繼承的方式來給原對象增加新功能,但是裝飾者模式采用組合的方式比生成子類更加靈活。
類圖及樣例實現(xiàn):
在裝飾模式中的各個角色有:
抽象構(gòu)件( Component )角色:給出一個抽象接口,以規(guī)范準(zhǔn)備接收附加責(zé)任的對象。
具體構(gòu)件( ConcreteComponent )角色:定義一個將要接收附加責(zé)任的類。
裝飾( Decorator )角色:持有一個構(gòu)件( Component )對象的實例,并定義一個與抽象構(gòu)件接口一致的接口。
具體裝飾( ConcreteDecorator )角色:負責(zé)給構(gòu)件對象 " 貼上 " 附加的責(zé)任。
#include <string> #include <iostream> #include <memory> using namespace std; //抽象類Tank class Tank { public: virtual void shot()=0; virtual void run()=0; public: virtual ~Tank() { cout<<"in the destructor of Tank"<<endl; } }; //具體類 T50 class T50:public Tank { public: void shot() { cout<<"Tank T50 shot()"<<endl; } void run() { cout<<"Tank T50 run()"<<endl; } public: virtual ~T50() { cout<<"In the destructor of T50"<<endl; } }; //具體類T75 class T75:public Tank { public: void shot() { cout<<"Tank T75 shot()"<<endl; } void run() { cout<<"Tank T75 run()"<<endl; } public: virtual ~T75() { cout<<"In the destructor of T75"<<endl; } }; //抽象類,Decorator class Decorator:public Tank { protected: Tank* tank; public: Decorator(Tank* tank):tank(tank) {} //具體的坦克的裝飾類 virtual ~Decorator() { cout<<"In the destructor of Decorator"<<endl; } public: void shot() { tank->shot(); } void run() { tank->run(); } }; class InfraredDecorator: public Decorator { private: string infrared;//這就是所謂的addAtrribute public: InfraredDecorator(Tank* tank):Decorator(tank) {} virtual ~InfraredDecorator() { cout<<"in the destructor of InfraredDecorator"<<endl; } public: void set_Infrared(const string &infrared) { this->infrared=infrared; } string get_infrared() const { return infrared; } void run() { tank->run(); set_Infrared("+Infrared"); cout<<get_infrared()<<endl; } void shot() { tank->shot(); } }; class AmphibianDecorator:public Decorator { private: string amphibian; public: AmphibianDecorator(Tank* tank):Decorator(tank) {} ~AmphibianDecorator() { cout<<"in the destructor of AmphibianDecorator"<<endl; } public: void set_amphibian(const string &hibian) { this->amphibian=hibian; } string get_amphibian() const { return amphibian; } public: void run() { tank->run(); set_amphibian("+amphibian"); cout<<get_amphibian()<<endl; } void shot() { tank->shot(); } }; int main(int argc, char **argv) { //給T50增加紅外功能 Tank* tank1(new T50); Tank* pid1(new InfraredDecorator(tank1)); pid1->shot(); cout<<endl; pid1->run(); cout<<endl; cout<<endl<<"---------------"<<endl; //給t75增加紅外、兩棲功能 Tank* tank2(new T75); tank2->run(); Tank* pid2(new InfraredDecorator(tank2)); Tank* pad2(new AmphibianDecorator(pid2)); pad2->shot(); cout<<endl; pad2->run(); cout<<endl; cout<<endl<<"--------------"<<endl; //動態(tài)撤銷其他裝飾 ? tank2->run(); Tank * tank3(tank2); tank3->run(); return 0; }
裝飾者與適配者模式的區(qū)別:
1. 關(guān)于新職責(zé):適配器也可以在轉(zhuǎn)換時增加新的職責(zé),但主要目的不在此。裝飾者模式主要是給被裝飾者增加新職責(zé)的。
2. 關(guān)于原接口:適配器模式是用新接口來調(diào)用原接口,原接口對新系統(tǒng)是不可見或者說不可用的。裝飾者模式原封不動的使用原接口,系統(tǒng)對裝飾的對象也通過原接口來完成使用。(增加新接口的裝飾者模式可以認為是其變種 -- “半透明”裝飾者)
3. 關(guān)于其包裹的對象:適配器是知道被適配者的詳細情況的(就是那個類或那個接口)。裝飾者只知道其接口是什么,至于其具體類型(是基類還是其他派生類)只有在運行期間才知道。
要點:
1 .裝飾者和被裝飾對象有相同的超類型。
2 .可以用一個或多個裝飾者包裝一個對象。
3 .裝飾者可以在所委托被裝飾者的行為之前或之后,加上自己的行為,以達到特定的目的。
4 .對象可以在任何時候被裝飾,所以可以在運行時動態(tài)的,不限量的用你喜歡的裝飾者來裝飾對象。
5 .裝飾模式中使用繼承的關(guān)鍵是想達到裝飾者和被裝飾對象的類型匹配,而不是獲得其行為。
6 .裝飾者一般對組件的客戶是透明的,除非客戶程序依賴于組件的具體類型。在實際項目中可以根據(jù)需要為裝飾者添加新的行為,做到 “ 半透明 ” 裝飾者。
適用場景與優(yōu)缺點:
在以下情況下應(yīng)當(dāng)使用裝飾模式:
1. 需要擴展一個類的功能,或給一個類增加附加責(zé)任。
2. 需要動態(tài)地給一個對象增加功能,這些功能可以再動態(tài)地撤銷。
3. 需要增加由一些基本功能的排列組合而產(chǎn)生的非常大量的功能,從而使繼承關(guān)系變得不現(xiàn)實。
優(yōu)點:
1.Decorator 模式與繼承關(guān)系的目的都是要擴展對象的功能,但是 Decorator 可以提供比繼承更多的靈活性。
2. 通過使用不同的具體裝飾類以及這些裝飾類的排列組合,設(shè)計師可以創(chuàng)造出很多不同行為的組合。
缺點:
1. 這種比繼承更加靈活機動的特性,也同時意味著更加多的復(fù)雜性。
2. 裝飾模式會導(dǎo)致設(shè)計中出現(xiàn)許多小類,如果過度使用,會使程序變得很復(fù)雜。
3. 裝飾模式是針對抽象組件( Component )類型編程。但是,如果你要針對具體組件編程時,就應(yīng)該重新思考你的應(yīng)用架構(gòu),以及裝飾者是否合適。當(dāng)然也可以改變 Component 接口,增加新的公開的行為,實現(xiàn) “ 半透明 ” 的裝飾者模式。在實際項目中要做出最佳選擇。
LCL_data原創(chuàng)于CSDN.NET【 http://blog.csdn.net/lcl_data/article/details/8830455 】
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
