設(shè)計(jì)模式之裝飾模式(學(xué)習(xí)筆記)
定義
裝飾模式(Decorator Pattern),又稱為包裝模式,是一種結(jié)構(gòu)型設(shè)計(jì)模式。它允許在不改變現(xiàn)有對(duì)象結(jié)構(gòu)的情況下,動(dòng)態(tài)地添加新的功能。通過(guò)將每個(gè)功能封裝在單獨(dú)的裝飾器類中,并且這些裝飾器類通過(guò)引用原始對(duì)象來(lái)實(shí)現(xiàn)功能的組合,從而提供了靈活性和可擴(kuò)展性的優(yōu)勢(shì)。裝飾模式避免了通過(guò)繼承方式增加功能所帶來(lái)的復(fù)雜性,使得功能的添加和組合更加高效和清晰。
為什么使用裝飾模式?
-
靈活性和可擴(kuò)展性
-
裝飾模式允許按需動(dòng)態(tài)地添加或移除對(duì)象的功能,而不會(huì)影響其他部分的代碼。
-
通過(guò)組合不同的裝飾器類,可以創(chuàng)建出多種不同的對(duì)象組合,以滿足不同的需求,避免了靜態(tài)繼承所帶來(lái)的類爆炸問(wèn)題。
-
單一職責(zé)原則
-
每個(gè)裝飾器類只關(guān)注于一個(gè)特定的功能或責(zé)任,這符合單一職責(zé)原則,使得代碼結(jié)構(gòu)更加清晰和易于維護(hù)。
-
透明性
-
裝飾器類與原始對(duì)象實(shí)現(xiàn)相同的接口,因此對(duì)客戶端來(lái)說(shuō)是透明的。
-
客戶端可以像使用原始對(duì)象一樣使用裝飾后的對(duì)象,無(wú)需關(guān)心對(duì)象內(nèi)部的具體裝飾結(jié)構(gòu)。
裝飾模式的實(shí)現(xiàn)步驟
-
抽象組件類
-
定義了被裝飾對(duì)象的接口,它可能是一個(gè)抽象類或接口,包含了所有具體組件類和裝飾器類都會(huì)實(shí)現(xiàn)的方法(抽象被裝飾者的行為)。
-
具體組件類
-
實(shí)現(xiàn)抽象組件接口,表示原始對(duì)象的基本行為或功能(繼承抽象組件類,被裝飾者行為的具體實(shí)現(xiàn))。
-
抽象裝飾器類
-
擴(kuò)展了抽象組件類,同時(shí)持有一個(gè)指向抽象組件對(duì)象的引用。
-
這個(gè)類可以選擇性地添加一些額外的行為,但其主要作用是通過(guò)引用調(diào)用原始對(duì)象的方法(繼承抽象組件類)。
-
具體裝飾器類
-
擴(kuò)展了抽象裝飾器類,通過(guò)在調(diào)用父類方法前后添加新的行為來(lái)實(shí)現(xiàn)功能的擴(kuò)展。
-
具體裝飾器類可以是多個(gè),可以互相組合,以形成復(fù)雜的裝飾結(jié)構(gòu)(繼承抽象裝飾器類)。
優(yōu)缺點(diǎn)和適用場(chǎng)景
優(yōu)點(diǎn)
-
靈活性
-
動(dòng)態(tài)地為對(duì)象添加功能,避免了靜態(tài)繼承的限制。
-
可擴(kuò)展性
-
通過(guò)組合不同的裝飾器類,可以實(shí)現(xiàn)多種功能組合,符合開(kāi)閉原則。
-
單一職責(zé)原則
-
每個(gè)裝飾器類只關(guān)注于一個(gè)功能,使得代碼結(jié)構(gòu)清晰。
缺點(diǎn)
-
復(fù)雜性增加
-
可能會(huì)導(dǎo)致裝飾器類的數(shù)量增加,增加了系統(tǒng)的復(fù)雜度和理解難度。
-
裝飾順序問(wèn)題
-
如果裝飾器的順序不正確,可能會(huì)影響最終的功能實(shí)現(xiàn)。
適用場(chǎng)景
-
動(dòng)態(tài)添加功能
-
當(dāng)需要?jiǎng)討B(tài)地為對(duì)象添加額外功能時(shí),而又不希望生成大量子類時(shí),可以使用裝飾模式。
-
透明且靈活地?cái)U(kuò)展對(duì)象的功能
-
當(dāng)需要透明且靈活地?cái)U(kuò)展對(duì)象的功能時(shí),裝飾模式尤為適用,例如在不影響其他對(duì)象的情況下動(dòng)態(tài)添加功能。
咖啡店的例子
假設(shè)我們有一個(gè)咖啡店,賣(mài)基礎(chǔ)的咖啡和各種附加調(diào)料(如牛奶、糖、巧克力等)。我們可以使用裝飾模式來(lái)實(shí)現(xiàn)這種功能擴(kuò)展。
#include <iostream> #include <memory> // 提供智能指針的定義和實(shí)現(xiàn) // 抽象組件類:咖啡 class Coffee { public: virtual ~Coffee() {} // 獲取咖啡描述的方法,純虛函數(shù) virtual std::string getDescription() const = 0; // 獲取咖啡價(jià)格的方法,純虛函數(shù) virtual double cost() const = 0; }; // 具體組件類:基本咖啡 class BasicCoffee : public Coffee { public: // 實(shí)現(xiàn)獲取描述的方法 std::string getDescription() const override { return "Basic Coffee"; } // 實(shí)現(xiàn)獲取價(jià)格的方法 double cost() const override { return 5.0; // 基本咖啡的價(jià)格 } }; // 抽象裝飾器類:咖啡裝飾器 class CoffeeDecorator : public Coffee { protected: // 持有一個(gè)指向被裝飾對(duì)象的指針 std::shared_ptr<Coffee> coffee; public: // 構(gòu)造函數(shù),接受一個(gè)被裝飾對(duì)象的指針 CoffeeDecorator(std::shared_ptr<Coffee> coffee) : coffee(coffee) {} // 實(shí)現(xiàn)獲取描述的方法,調(diào)用被裝飾對(duì)象的方法 std::string getDescription() const override { return coffee->getDescription(); } // 實(shí)現(xiàn)獲取價(jià)格的方法,調(diào)用被裝飾對(duì)象的方法 double cost() const override { return coffee->cost(); } }; // 具體裝飾器類:牛奶裝飾器 class MilkDecorator : public CoffeeDecorator { public: // 構(gòu)造函數(shù),接受一個(gè)被裝飾對(duì)象的指針 MilkDecorator(std::shared_ptr<Coffee> coffee) : CoffeeDecorator(coffee) {} // 實(shí)現(xiàn)獲取描述的方法,添加牛奶的描述 std::string getDescription() const override { return coffee->getDescription() + ", Milk"; } // 實(shí)現(xiàn)獲取價(jià)格的方法,添加牛奶的價(jià)格 double cost() const override { return coffee->cost() + 1.5; // 牛奶的價(jià)格 } }; // 具體裝飾器類:糖裝飾器 class SugarDecorator : public CoffeeDecorator { public: // 構(gòu)造函數(shù),接受一個(gè)被裝飾對(duì)象的指針 SugarDecorator(std::shared_ptr<Coffee> coffee) : CoffeeDecorator(coffee) {} // 實(shí)現(xiàn)獲取描述的方法,添加糖的描述 std::string getDescription() const override { return coffee->getDescription() + ", Sugar"; } // 實(shí)現(xiàn)獲取價(jià)格的方法,添加糖的價(jià)格 double cost() const override { return coffee->cost() + 0.5; // 糖的價(jià)格 } }; int main() { // 創(chuàng)建一個(gè)基本咖啡對(duì)象 std::shared_ptr<Coffee> basicCoffee = std::make_shared<BasicCoffee>(); std::cout << "Description: " << basicCoffee->getDescription() << ", Cost: " << basicCoffee->cost() << " RMB" << std::endl; // 用牛奶裝飾基本咖啡 std::shared_ptr<Coffee> coffeeWithMilk = std::make_shared<MilkDecorator>(basicCoffee); std::cout << "Description: " << coffeeWithMilk->getDescription() << ", Cost: " << coffeeWithMilk->cost() << " RMB" << std::endl; // 再用糖裝飾已加牛奶的咖啡 std::shared_ptr<Coffee> coffeeWithMilkAndSugar = std::make_shared<SugarDecorator>(coffeeWithMilk); std::cout << "Description: " << coffeeWithMilkAndSugar->getDescription() << ", Cost: " << coffeeWithMilkAndSugar->cost() << " RMB" << std::endl; return 0; }

浙公網(wǎng)安備 33010602011771號(hào)