C++實現(xiàn)設(shè)計模式之裝飾者模式詳解
設(shè)計模式和設(shè)計原則
裝飾者模式動態(tài)地將責任附加到對象上。若要擴展功能,裝飾者模式提供了比繼承更有彈性的替代方案。
裝飾者模式遵循的設(shè)計原則:
類應(yīng)該對擴展開放,對修改關(guān)閉。
裝飾者模式中的類
裝飾者模式中的類如下圖,C++設(shè)計模式之裝飾模式
其中Component抽象組件類,即被裝飾的類,每個組件都可以單獨使用,或者被裝飾者包起來使用。該類中聲明了一些接口,這些接口將在具體組件,以及具體裝飾者中實現(xiàn)。
ConcreteComponent具體組件類,繼承自組件類,是我們要動態(tài)地加上新行為(即要裝飾)的對象。
Decorator抽象裝飾者類是具體裝飾者的基類,裝飾者類中包含一個組件類型的指針,是為了記錄被裝飾的對象。當需要獲得裝飾之后的行為時可以通過該指針獲得被裝飾者的行為加上裝飾者自身的行為,這個在下面案例中會看到。
ConcreteDecorator具體裝飾者類,裝飾者類要實現(xiàn)Decorator中定義的方法,另外可以加一些新的方法。
如上圖所示裝飾者和被裝飾者必須是一樣地類型,也就是有共同地超類,這是相當關(guān)鍵的地方。這是因為裝飾者必須能取代被裝飾者。
案列描述
咖啡館提供各種各樣的咖啡,每種咖啡可以加不同調(diào)料(摩卡、奶泡,雙糖,半糖等)。以飲料為抽象組件,各種各樣的咖啡為具體組件,咖啡中的不同調(diào)料為裝飾者。每種咖啡以及調(diào)料有各自的描述和價格,使用裝飾者模式,加了不同調(diào)料的咖啡也可以輕松給出描述和價格。
下面例子中生產(chǎn)三種咖啡:不加調(diào)料的Espresso、加雙倍摩卡一份奶泡的DarkRoast和加雙倍奶泡一份摩卡的HouseBlend.。
代碼實現(xiàn)
聲明:類的聲明和實現(xiàn)在同一個文件里是個壞習(xí)慣,壞習(xí)慣,壞習(xí)慣,但因為我懶,還是寫一起了,大家不要效仿,要引以為戒,要引以為戒,要引以為戒。
首先定義抽象組件類Beverage和抽象裝飾者類CondimentDecorator,代碼如下。這里關(guān)鍵的地方是抽象裝飾者繼承自抽象組件,且包含一個抽象組件的引用。
//抽象組件類-飲料 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ù),是為了強制子類實例化時必須實現(xiàn)它。 protected: Beverage* m_beverage; };
然后定義具體組件,即三種具體的咖啡DarkRoast、Espresso和HouseBlend。
//三個具體組件 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; } };
再定義兩個具體裝飾者類,即兩種調(diào)料Mocha和Milk。
//兩個具體裝飾者 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ù)中寫測試代碼,生產(chǎn)三種咖啡:不加調(diào)料的Espresso、加雙倍摩卡一份奶泡的DarkRoast和加雙倍奶泡一份摩卡的HouseBlend.
//測試代碼 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; }
運行結(jié)果
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
QTableWidget設(shè)置只讓某一列可編輯的實現(xiàn)
本文介紹了如何將QTableWidget的某一列設(shè)置為可編輯,以便用戶可以輸入自定義數(shù)據(jù),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08解決c++?error:crosses?initialization?of?問題
最近在寫代碼的時候,碰到了?crosses?initialization?of?...?的問題,只因我在?switch?的某個?case?分支下定義了一個變量,于是乎便將這個問題整理一下,需要的朋友可以參考下2023-03-03C++實現(xiàn)學(xué)生考勤信息管理系統(tǒng)
這篇文章主要為大家詳細介紹了C++實現(xiàn)學(xué)生考勤信息管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-12-12Qt數(shù)據(jù)庫應(yīng)用之實現(xiàn)通用數(shù)據(jù)庫采集
這篇文章主要為大家介紹了Qt中是如何實現(xiàn)通用數(shù)據(jù)庫采集的,文中的示例代碼講解詳細,對我們學(xué)習(xí)Qt有一定幫助,感興趣的小伙伴可以了解一下2022-03-03

C++??STL?_?Vector使用及模擬實現(xiàn)

C++ 中"emplace_back" 與 "push_back" 的區(qū)別