C++實(shí)現(xiàn)設(shè)計(jì)模式之裝飾者模式詳解
設(shè)計(jì)模式和設(shè)計(jì)原則
裝飾者模式動(dòng)態(tài)地將責(zé)任附加到對(duì)象上。若要擴(kuò)展功能,裝飾者模式提供了比繼承更有彈性的替代方案。
裝飾者模式遵循的設(shè)計(jì)原則:
類應(yīng)該對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉。
裝飾者模式中的類
裝飾者模式中的類如下圖,C++設(shè)計(jì)模式之裝飾模式

其中Component抽象組件類,即被裝飾的類,每個(gè)組件都可以單獨(dú)使用,或者被裝飾者包起來(lái)使用。該類中聲明了一些接口,這些接口將在具體組件,以及具體裝飾者中實(shí)現(xiàn)。
ConcreteComponent具體組件類,繼承自組件類,是我們要?jiǎng)討B(tài)地加上新行為(即要裝飾)的對(duì)象。
Decorator抽象裝飾者類是具體裝飾者的基類,裝飾者類中包含一個(gè)組件類型的指針,是為了記錄被裝飾的對(duì)象。當(dāng)需要獲得裝飾之后的行為時(shí)可以通過(guò)該指針獲得被裝飾者的行為加上裝飾者自身的行為,這個(gè)在下面案例中會(huì)看到。
ConcreteDecorator具體裝飾者類,裝飾者類要實(shí)現(xiàn)Decorator中定義的方法,另外可以加一些新的方法。
如上圖所示裝飾者和被裝飾者必須是一樣地類型,也就是有共同地超類,這是相當(dāng)關(guān)鍵的地方。這是因?yàn)檠b飾者必須能取代被裝飾者。
案列描述
咖啡館提供各種各樣的咖啡,每種咖啡可以加不同調(diào)料(摩卡、奶泡,雙糖,半糖等)。以飲料為抽象組件,各種各樣的咖啡為具體組件,咖啡中的不同調(diào)料為裝飾者。每種咖啡以及調(diào)料有各自的描述和價(jià)格,使用裝飾者模式,加了不同調(diào)料的咖啡也可以輕松給出描述和價(jià)格。
下面例子中生產(chǎn)三種咖啡:不加調(diào)料的Espresso、加雙倍摩卡一份奶泡的DarkRoast和加雙倍奶泡一份摩卡的HouseBlend.。
代碼實(shí)現(xiàn)
聲明:類的聲明和實(shí)現(xiàn)在同一個(gè)文件里是個(gè)壞習(xí)慣,壞習(xí)慣,壞習(xí)慣,但因?yàn)槲覒校€是寫一起了,大家不要效仿,要引以為戒,要引以為戒,要引以為戒。
首先定義抽象組件類Beverage和抽象裝飾者類CondimentDecorator,代碼如下。這里關(guān)鍵的地方是抽象裝飾者繼承自抽象組件,且包含一個(gè)抽象組件的引用。
//抽象組件類-飲料
class Beverage
{
public:
Beverage() :m_description("Unknown Beverage")
{
}
virtual std::string getDescription(){ return m_description; }
virtual double cost() = 0;
protected:
std::string m_description;
};
//抽象裝飾者類-調(diào)料,繼承自飲料類
class CondimentDecorator :public Beverage
{
public:
CondimentDecorator(Beverage* berverge)
:m_beverage(berverge)
{
}
virtual std::string getDescription() = 0;//定義成純虛函數(shù),是為了強(qiáng)制子類實(shí)例化時(shí)必須實(shí)現(xiàn)它。
protected:
Beverage* m_beverage;
};
然后定義具體組件,即三種具體的咖啡DarkRoast、Espresso和HouseBlend。
//三個(gè)具體組件
class DarkRoast :public Beverage
{
public:
DarkRoast()
{
m_description = "DarkRoast";
}
double cost()
{
return 2.99;
}
};
class Espresso :public Beverage
{
public:
Espresso()
{
m_description = "Espresso";
}
double cost()
{
return 1.99;
}
};
class HouseBlend :public Beverage
{
public:
HouseBlend()
{
m_description = "HouseBlend";
}
double cost()
{
return 0.89;
}
};
再定義兩個(gè)具體裝飾者類,即兩種調(diào)料Mocha和Milk。
//兩個(gè)具體裝飾者
class Mocha :public CondimentDecorator
{
public:
Mocha(Beverage* beverage) :CondimentDecorator(beverage)
{
}
std::string getDescription()
{
return m_beverage->getDescription() + " Mocha";
}
double cost()
{
return 0.2 + m_beverage->cost();
}
};
class Milk :public CondimentDecorator
{
public:
Milk(Beverage* beverage) :CondimentDecorator(beverage)
{
}
std::string getDescription()
{
return m_beverage->getDescription() + " Milk";
}
double cost()
{
return 0.5 + m_beverage->cost();
}
};
最后在main函數(shù)中寫測(cè)試代碼,生產(chǎn)三種咖啡:不加調(diào)料的Espresso、加雙倍摩卡一份奶泡的DarkRoast和加雙倍奶泡一份摩卡的HouseBlend.
//測(cè)試代碼
int main()
{
//不加調(diào)料的Espresso
Beverage* beverage = new Espresso();
std::cout << beverage->getDescription() << " ¥" << beverage->cost() << std::endl;
//加雙倍摩卡和奶泡的DarkRoast
Beverage* beverage2 = new DarkRoast();
beverage2 = new Mocha(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Milk(beverage2);
std::cout << beverage2->getDescription() << " ¥" << beverage2->cost() << std::endl;
//加雙倍奶泡的和一份摩卡的HouseBlend
Beverage* beverage3 = new HouseBlend();
beverage3 = new Mocha(beverage3);
beverage3 = new Milk(beverage3);
beverage3 = new Milk(beverage3);
std::cout << beverage3->getDescription() << " ¥" << beverage3->cost() << std::endl;
system("pause");
delete beverage;
delete beverage2;
delete beverage3;
}
運(yùn)行結(jié)果

總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
QTableWidget設(shè)置只讓某一列可編輯的實(shí)現(xiàn)
本文介紹了如何將QTableWidget的某一列設(shè)置為可編輯,以便用戶可以輸入自定義數(shù)據(jù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08
C語(yǔ)言中關(guān)于計(jì)算字符串長(zhǎng)度的幾種方式
這篇文章主要介紹了C語(yǔ)言中關(guān)于計(jì)算字符串長(zhǎng)度的幾種方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
解決c++?error:crosses?initialization?of?問(wèn)題
最近在寫代碼的時(shí)候,碰到了?crosses?initialization?of?...?的問(wèn)題,只因我在?switch?的某個(gè)?case?分支下定義了一個(gè)變量,于是乎便將這個(gè)問(wèn)題整理一下,需要的朋友可以參考下2023-03-03
C++實(shí)現(xiàn)學(xué)生考勤信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)學(xué)生考勤信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12
Qt數(shù)據(jù)庫(kù)應(yīng)用之實(shí)現(xiàn)通用數(shù)據(jù)庫(kù)采集
這篇文章主要為大家介紹了Qt中是如何實(shí)現(xiàn)通用數(shù)據(jù)庫(kù)采集的,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Qt有一定幫助,感興趣的小伙伴可以了解一下2022-03-03
C++??STL?_?Vector使用及模擬實(shí)現(xiàn)
C++ 中"emplace_back" 與 "push_back" 的區(qū)別
C語(yǔ)言實(shí)現(xiàn)火車票管理系統(tǒng)

