7,裝飾者模式(Decorator Pattern)動態的給一個對象添加一些額外的職責。就增加功能來說,此模式比生成子類更為靈活。繼承關系的一個替換方案。
裝飾( Decorator )模式又叫做包裝模式。通過一種對客戶端透明的方式來擴展對象的功能,是繼承關系的一個替換方案。
裝飾模式就是把要添加的附加功能分別放在單獨的類中,並讓這個類包含它要裝飾的對象,當需要執行時,客戶端就可以有選擇地、按順序地使用裝飾功能包裝對象。
在裝飾模式中的各個角色有:
抽象構件(Component)角色:給出一個抽象接口,以規範準備接收附加責任的對象。
具體構件(Concrete Component)角色:定義一個將要接收附加責任的類。
裝飾(Decorator)角色:持有一個構件(Component)對象的實例,並定義一個與抽象構件接口一致的接口。
具體裝飾(Concrete Decorator)角色:負責給構件對象"貼上"附加的責任。
實例一
1 #include <string> 2 #include <iostream> 3 #include <memory> 4 using namespace std; 5 6 //抽象類Tank 抽象構件(Component)角色:給出一個抽象接口,以規範準備接收附加責任的對象。 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 具體構件(Concrete Component)角色:定義一個將要接收附加責任的類。 20 class T50:public Tank 21 { 22 public: 23 voidshot() 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 具體構件(Concrete Component)角色:定義一個將要接收附加責任的類。 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 裝飾(Decorator)角色:持有一個構件(Component)對象的實例,並定義一個與抽象構件接口一致的接口。 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 // 具體裝飾(Concrete Decorator)角色:負責給構件對象"貼上"附加的責任 紅外線Infrared 。 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 // 具體裝飾 水路兩棲Amphibian 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 #include <iostream> 2 using namespace std; 3 4 class Car 5 { 6 public: 7 virtual void show() = 0; 8 }; 9 10 class RunCar : public Car 11 { 12 public: 13 virtual void show() 14 { 15 cout << "可以跑" << endl; 16 } 17 protected: 18 private: 19 }; 20 21 22 class SwimCarDirector : public Car 23 { 24 public: 25 SwimCarDirector(Car *car) 26 { 27 m_car = car; 28 } 29 void swim() 30 { 31 cout << "可以遊" << endl; 32 } 33 virtual void show() 34 { 35 m_car->show(); 36 swim(); 37 } 38 protected: 39 private: 40 Car *m_car; 41 }; 42 43 class FlyCarDirector : public Car 44 { 45 public: 46 FlyCarDirector(Car *car) 47 { 48 m_car = car; 49 } 50 void fly() 51 { 52 cout << "可以飛" << endl; 53 } 54 virtual void show() 55 { 56 m_car->show(); 57 fly(); 58 } 59 60 private: 61 Car *m_car; 62 }; 63 64 void main() 65 { 66 Car * mycar = NULL; 67 mycar = new RunCar; 68 printf("-----000\n"); 69 mycar->show(); 70 71 printf("-----aaa\n"); 72 73 FlyCarDirector *flycar = new FlyCarDirector(mycar); 74 flycar->show(); 75 76 printf("-----bbb\n"); 77 SwimCarDirector *swimcar = new SwimCarDirector(flycar); 78 swimcar->show(); 79 80 delete swimcar; 81 delete flycar; 82 delete mycar; 83 system("pause"); 84 return ; 85 }
裝飾者與適配者模式的區別:
1.關於新職責:適配器也可以在轉換時增加新的職責,但主要目的不在此。裝飾者模式主要是給被裝飾者增加新職責的。
2.關於原接口:適配器模式是用新接口來調用原接口,原接口對新系統是不可見或者說不可用的。裝飾者模式原封不動的使用原接口,系統對裝飾的對象也通過原接口來完成使用。(增加新接口的裝飾者模式可以認為是其變種--“半透明”裝飾者)
3.關於其包裹的對象:適配器是知道被適配者的詳細情況的(就是那個類或那個接口)。裝飾者只知道其接口是什麽,至於其具體類型(是基類還是其他派生類)只有在運行期間才知道。
要點:
1. 裝飾者和被裝飾對象有相同的超類型。
2. 可以用一個或多個裝飾者包裝一個對象。
3. 裝飾者可以在所委托被裝飾者的行為之前或之後,加上自己的行為,以達到特定的目的。
4. 對象可以在任何時候被裝飾,所以可以在運行時動態的,不限量的用你喜歡的裝飾者來裝飾對象。
5. 裝飾模式中使用繼承的關鍵是想達到裝飾者和被裝飾對象的類型匹配,而不是獲得其行為。
6. 裝飾者一般對組件的客戶是透明的,除非客戶程序依賴於組件的具體類型。在實際項目中可以根據需要為裝飾者添加新的行為,做到“半透明”裝飾者。
適用場景與優缺點:
在以下情況下應當使用裝飾模式:
1.需要擴展一個類的功能,或給一個類增加附加責任。
2.需要動態地給一個對象增加功能,這些功能可以再動態地撤銷。
3.需要增加由一些基本功能的排列組合而產生的非常大量的功能,從而使繼承關系變得不現實。
優點:
1. Decorator模式與繼承關系的目的都是要擴展對象的功能,但是Decorator可以提供比繼承更多的靈活性。
2. 通過使用不同的具體裝飾類以及這些裝飾類的排列組合,設計師可以創造出很多不同行為的組合。
缺點:
1. 這種比繼承更加靈活機動的特性,也同時意味著更加多的復雜性。
2. 裝飾模式會導致設計中出現許多小類,如果過度使用,會使程序變得很復雜。
3. 裝飾模式是針對抽象組件(Component)類型編程。但是,如果你要針對具體組件編程時,就應該重新思考你的應用架構,以及裝飾者是否合適。當然也可以改變Component接口,增加新的公開的行為,實現“半透明”的裝飾者模式。在實際項目中要做出最佳選擇。
7,裝飾者模式(Decorator Pattern)動態的給一個對象添加一些額外的職責。就增加功能來說,此模式比生成子類更為靈活。繼承關系的一個替換方案。