我所理解的設計模式(C++實現)——裝飾者模式(Decorator Pattern)

來源:互聯網
上載者:User

解決的問題:

我們在裝飾新家的時候買了幾幅抽象畫,買回來之後發現有些加上色彩豔麗的邊框更適合我們,而有的加上玻璃罩之後更能符合我們的使用。那我們來怎麼解決這個問題呢?他需要動態給別的對象增加額外的職責,這就是裝飾者模式的目的。

我們可以通過繼承的方式來給原對象增加新功能,但是裝飾者模式採用組合的方式比產生子類更加靈活。

類圖及範例實現:

在裝飾模式中的各個角色有:

抽象構件(Component)角色:給出一個抽象介面,以規範準備接收附加責任的對象。

具體構件(Concrete Component)角色:定義一個將要接收附加責任的類。

裝飾(Decorator)角色:持有一個構件(Component)對象的執行個體,並定義一個與抽象構件介面一致的介面。

具體裝飾(Concrete Decorator)角色:負責給構件對象"貼上"附加的責任。

[cpp] view plaincopy
  1. #include <string>  
  2. #include <iostream>  
  3. #include <memory>  
  4. using namespace std;  
  5.   
  6. //抽象類別Tank  
  7. class Tank  
  8. {  
  9. public:  
  10.     virtual void shot()=0;  
  11.     virtual void run()=0;  
  12.   
  13. public:  
  14.     virtual ~Tank()  
  15.     {  
  16.         cout<<"in the destructor of Tank"<<endl;  
  17.     }     
  18. };  
  19. //具體類 T50  
  20. class T50:public Tank  
  21. {  
  22. public:  
  23.     void shot()  
  24.     {  
  25.         cout<<"Tank T50 shot()"<<endl;  
  26.     }  
  27.     void run()  
  28.     {  
  29.         cout<<"Tank T50 run()"<<endl;  
  30.     }  
  31. public:  
  32.     virtual ~T50()  
  33.     {  
  34.         cout<<"In the destructor of T50"<<endl;  
  35.     }  
  36. };  
  37. //具體類T75  
  38. class T75:public Tank  
  39. {  
  40. public:  
  41.     void shot()  
  42.     {  
  43.         cout<<"Tank T75 shot()"<<endl;  
  44.     }  
  45.     void run()  
  46.     {  
  47.         cout<<"Tank T75 run()"<<endl;  
  48.     }  
  49. public:  
  50.     virtual ~T75()  
  51.     {  
  52.         cout<<"In the destructor of T75"<<endl;  
  53.     }  
  54. };  
  55.   
  56. //抽象類別,Decorator  
  57. class Decorator:public Tank  
  58. {  
  59. protected:  
  60.     Tank* tank;  
  61. public:  
  62.     Decorator(Tank* tank):tank(tank) {}  //具體的坦克的裝飾類  
  63.     virtual ~Decorator()  
  64.     {  
  65.         cout<<"In the destructor of Decorator"<<endl;  
  66.     }  
  67. public:  
  68.     void shot()  
  69.     {  
  70.         tank->shot();  
  71.     }  
  72.     void run()  
  73.     {  
  74.         tank->run();  
  75.     }  
  76. };  
  77.   
  78. class InfraredDecorator: public Decorator  
  79. {  
  80. private:  
  81.     string infrared;//這就是所謂的addAtrribute  
  82. public:  
  83.     InfraredDecorator(Tank* tank):Decorator(tank) {}  
  84.     virtual ~InfraredDecorator()  
  85.     {  
  86.         cout<<"in the destructor of InfraredDecorator"<<endl;  
  87.     }  
  88. public:  
  89.     void set_Infrared(const string &infrared)  
  90.     {  
  91.         this->infrared=infrared;  
  92.     }  
  93.     string get_infrared() const  
  94.     {  
  95.         return infrared;  
  96.     }  
  97.     void run()  
  98.     {  
  99.         tank->run();  
  100.         set_Infrared("+Infrared");  
  101.         cout<<get_infrared()<<endl;  
  102.     }  
  103.     void shot()  
  104.     {  
  105.         tank->shot();  
  106.     }  
  107. };  
  108.   
  109. class AmphibianDecorator:public Decorator  
  110. {  
  111. private:  
  112.     string amphibian;  
  113. public:  
  114.     AmphibianDecorator(Tank* tank):Decorator(tank) {}  
  115.     ~AmphibianDecorator()  
  116.     {  
  117.         cout<<"in the destructor of AmphibianDecorator"<<endl;  
  118.     }  
  119. public:  
  120.     void set_amphibian(const string &hibian)  
  121.     {  
  122.         this->amphibian=hibian;  
  123.     }  
  124.     string get_amphibian() const  
  125.     {  
  126.         return amphibian;  
  127.     }  
  128. public:  
  129.     void run()  
  130.     {  
  131.         tank->run();  
  132.         set_amphibian("+amphibian");  
  133.         cout<<get_amphibian()<<endl;  
  134.     }  
  135.     void shot()  
  136.     {  
  137.         tank->shot();  
  138.     }  
  139. };  
  140.   
  141. int main(int argc, char **argv)  
  142. {  
  143.     //給T50增加紅外功能  
  144.     Tank* tank1(new T50);  
  145.     Tank* pid1(new InfraredDecorator(tank1));  
  146.     pid1->shot();  
  147.     cout<<endl;  
  148.     pid1->run();  
  149.     cout<<endl;  
  150.     cout<<endl<<"---------------"<<endl;  
  151.     //給t75增加紅外、兩棲功能  
  152.     Tank* tank2(new T75);  
  153.     tank2->run();  
  154.     Tank* pid2(new InfraredDecorator(tank2));  
  155.     Tank* pad2(new AmphibianDecorator(pid2));  
  156.     pad2->shot();  
  157.     cout<<endl;  
  158.     pad2->run();  
  159.     cout<<endl;  
  160.     cout<<endl<<"--------------"<<endl;  
  161.   
  162.     //動態撤銷其他裝飾 ?  
  163.     tank2->run();  
  164.   
  165.     Tank * tank3(tank2);  
  166.     tank3->run();  
  167.     return 0;  
  168. }  

 

裝飾者與適配者模式的區別:

1.關於新職責:適配器也可以在轉換時增加新的職責,但主要目的不在此。裝飾者模式主要是給被裝飾者增加新職責的。

2.關於原介面:適配器模式是用新介面來調用原介面,原介面對新系統是不可見或者說停用。裝飾者模式原封不動的使用原介面,系統對裝飾的對象也通過原介面來完成使用。(增加新介面的裝飾者模式可以認為是其變種--“半透明”裝飾者)

3.關於其包裹的對象:適配器是知道被適配者的詳細情況的(就是那個類或那個介面)。裝飾者只知道其介面是什麼,至於其具體類型(是基類還是其他衍生類別)只有在運行期間才知道。


要點:

1. 裝飾者和被裝飾對象有相同的超類型。

2. 可以用一個或多個裝飾者封裝一個對象。

3. 裝飾者可以在所委託被裝飾者的行為之前或之後,加上自己的行為,以達到特定的目的。

4. 對象可以在任何時候被裝飾,所以可以在運行時動態,不限量的用你喜歡的裝飾者來裝飾對象。

5. 裝飾模式中使用繼承的關鍵是想達到裝飾者和被裝飾對象的類型匹配,而不是獲得其行為。

6. 裝飾者一般對組件的客戶是透明的,除非客戶程式依賴於組件的具體類型。在實際項目中可以根據需要為裝飾者添加新的行為,做到“半透明”裝飾者。

適用情境與優缺點:在以下情況下應當使用裝飾模式:

1.需要擴充一個類的功能,或給一個類增加附加責任。 

2.需要動態地給一個對象增加功能,這些功能可以再動態地撤銷。 

3.需要增加由一些準系統的排列組合而產生的非常大量的功能,從而使繼承關係變得不現實。

優點:

1. Decorator模式與繼承關係的目的都是要擴充項物件的功能,但是Decorator可以提供比繼承更多的靈活性。

2. 通過使用不同的具體裝飾類以及這些裝飾類的排列組合,設計師可以創造出很多不同行為的組合。

缺點:

1. 這種比繼承更加靈活機動的特性,也同時意味著更加多的複雜性。

2. 裝飾模式會導致設計中出現許多小類,如果過度使用,會使程式變得很複雜。

3. 裝飾模式是針對抽象組件(Component)類型編程。但是,如果你要針對具體組件編程時,就應該重新思考你的應用架構,以及裝飾者是否合適。當然也可以改變Component介面,增加新的公開的行為,實現“半透明”的裝飾者模式。在實際項目中要做出最佳選擇。


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.