概念
裝飾模式:動態地給一個對象添加一些額外的職責。就增加功能來說,裝飾器模式相比生成子類更爲靈活。
允許向一個現有的對象添加新的功能,同時又不改變其結構
優點:裝飾類和被裝飾類可以獨立發展,不會相互耦合,裝飾模式是繼承的一個替代模式,裝飾模式可以動態擴展一個實現類的功能。
缺點:多層裝飾比較複雜。
應用場景
- 在不想增加很多子類的情況下擴展類。
- 動態增加功能,動態撤銷。
一般步驟
- 定義一個基類,並帶有一個功能的函數。如:Person類裏有個Show()功能;
class Person { public: Person(){}; Person(string name) { this->name = name; } ~Person() {} virtual void Show() // 展示裝扮 { cout << "裝扮的" << name << endl; } private: string name; };
- 定義一個裝飾類,繼承前面的基類,並且有一個裝飾的函數可以裝飾基類的指針,且重寫基類的那個功能函數(Show),並在函數裏調用基類的功能函數(Show);
這一步非常關鍵,是這個模式裏最重要的一步class Finery : public Person // 裝飾類 { public: void Decorate(Person* person) // 裝扮指定的人,在這個模式裏最重要的一個函數 { boy = person; } void Show() { if (boy) { boy->Show(); } } private: Person* boy; };
- 定義具體的功能類,繼承前面的裝飾類,且重寫功能函數(Show);
class TShirt : public Finery { public: void Show() { printf("Tshirt "); Finery::Show(); } }; class BigTrouser : public Finery { public: void Show() { printf("BigTrouser "); Finery::Show(); } };
完整實例
#include <cstdio>
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
Person(){};
Person(string name)
{
this->name = name;
}
~Person() {}
virtual void Show() // 展示裝扮
{
cout << "裝扮的" << name << endl;
}
private:
string name;
};
class Finery : public Person // 裝飾類
{
public:
void Decorate(Person* person) // 裝扮指定的人,在這個模式裏最重要的一個函數
{
boy = person;
}
void Show()
{
if (boy)
{
boy->Show();
}
}
private:
Person* boy;
};
class TShirt : public Finery
{
public:
void Show()
{
printf("Tshirt ");
Finery::Show();
}
};
class BigTrouser : public Finery
{
public:
void Show()
{
printf("BigTrouser ");
Finery::Show();
}
};
int main()
{
Person *xc = new Person("小菜");
cout << "第一鍾裝扮" << endl;
TShirt *tshirt = new TShirt();
BigTrouser *BigTrouser = new BigTrouser();
tshirt->Decorate(xc); // 用T恤裝扮小菜
BigTrouser->Decorate(tshirt); // 用褲子 裝扮 "已裝扮了T恤" 的小菜
BigTrouser->Show();
return 0;
}
參考資料
程傑老師的《大話設計模式》
裝飾器模式|菜鳥教程