英文叫Decorator Pattern,又叫裝飾者模式。裝飾模式是在不必改變原類文件和使用繼承的情況下,動態地擴展一個對象的功能。它是通過創建一個包裝對象,也就是裝飾來包裹真實的對象。(百度百科)
裝飾模式就是把要添加的附加功能分別放在單獨的類中,並讓這個類包含它要裝飾的對象,當需要執行時,客戶端就可以有選擇地、按順序地使用裝飾功能包裝對象。類與對象圖如下所示:
適用情況:
- 需要擴展一個類的功能,或給一個類添加附加職責。
- 需要動態的給一個對象添加功能,這些功能可以再動態的撤銷。
- 需要增加由一些基本功能的排列組合而產生的非常大量的功能,從而使繼承關係變的不現實。
- 當不能採用生成子類的方法進行擴充時。一種情況是,可能有大量獨立的擴展,爲支持每一種組合將產生大量的子類,使得子類數目呈爆炸性增長。另一種情況可能是因爲類定義被隱藏,或類定義不能用於生成子類。
舉例:
#include <iostream>
using namespace std;
/************************************************************************/
/* 問題描述:奶茶店需要設計一個系統,有不同的奶茶,例如,柃檬水,柚子茶,咖啡.....
同時這些飲料可以添加不同的調料,例如,糖、牛奶,豆漿、冰塊.....
未來還會推出新的飲料和配料
*/
/************************************************************************/
//抽象總基類
class Beverage
{
public:
virtual double cost() = 0;
virtual string getDescription()
{
return m_description = "Unknow Beveraage";
}
public:
string m_description;
};
//檸檬水
class LemonWater : public Beverage
{
public:
LemonWater()
{
m_description = "檸檬水";
}
double cost()
{
return 5.0;
}
string getDescription()
{
return m_description;
}
};
//綠茶
class GreenTea : public Beverage
{
public:
GreenTea()
{
m_description = "綠茶";
}
double cost()
{
return 3;
}
string getDescription()
{
return m_description;
}
};
//咖啡
class Coffee : public Beverage
{
public:
Coffee()
{
m_description = "咖啡";
}
double cost()
{
return 10;
}
string getDescription()
{
return m_description;
}
};
//裝飾者抽象基類
class Decorate : public Beverage{};
//裝飾者 -糖
class Suger : public Decorate
{
public:
Suger(Beverage *beverage)
{
m_beverage = beverage;
}
string getDescription()
{
return m_beverage->getDescription() + ",糖";
}
double cost()
{
return m_beverage->cost() + 5;
}
private:
Beverage *m_beverage;
};
//裝飾者 -牛奶
class Milk : public Decorate
{
public:
Milk(Beverage *beverage)
{
m_beverage = beverage;
}
string getDescription()
{
return m_beverage->getDescription() + ",牛奶";
}
double cost()
{
return m_beverage->cost() + 5;
}
private:
Beverage *m_beverage;
};
//裝飾者 -香精
class Essence : public Decorate
{
public:
Essence(Beverage *beverage)
{
m_beverage = beverage;
}
string getDescription()
{
return m_beverage->getDescription() + ",香精";
}
double cost()
{
return m_beverage->cost() + 5;
}
private:
Beverage *m_beverage;
};
int main(int argc, char *args[])
{
//1.來一杯檸檬水,什麼都不需要
Beverage *lemenWater = new LemonWater;
cout << "飲料名稱:" << lemenWater->getDescription().c_str()
<<" 價格:"<<lemenWater->cost()<< endl;
//2.來一杯加糖和香精的綠茶
Beverage *greenTea = new GreenTea;
greenTea = new Suger(greenTea);
greenTea = new Essence(greenTea);
cout << "飲料名稱:" << greenTea->getDescription().c_str()
<< " 價格:" << greenTea->cost() << endl;
//3.來一杯加糖,加牛奶,加香精的咖啡
Beverage *coffe = new Coffee;
coffe = new Suger(coffe);
coffe = new Milk(coffe);
coffe = new Essence(coffe);
cout << "飲料名稱:" << coffe->getDescription().c_str()
<< " 價格:" << coffe->cost() << endl;
getchar();
return 0;
}
運行結果:
由此可見裝飾者模式是在運行時動態的擴展對象功能,而繼承是在編譯時期就已經決定了對象的功能,因此裝飾者模式比繼承更爲靈活。
軟件設計發展的理念就是儘可能的在增加代碼的可擴展性的同事避免對原有代碼的修改,減輕工作負擔,也就是 類應設計的對擴展開放,對修改關閉。