長沙網(wǎng)絡(luò)公司網(wǎng)站網(wǎng)絡(luò)seo啥意思
從C++編程入手設(shè)計模式——裝飾器模式
? 我們今天玩裝飾器模式。在寫代碼的時候,我們經(jīng)常會遇到這樣的需求:在不修改原有類的情況下,給它增加一些額外的功能。比如你已經(jīng)有一個文本打印類,但現(xiàn)在你想讓它打印出來的內(nèi)容自動加上引號、變成大寫,甚至加上前綴或后綴。你可能第一反應(yīng)是繼承,但如果裝飾的方式有很多種,繼承的子類就會變得非常多,既麻煩又不靈活。裝飾器設(shè)計模式就是為了解決這個問題的。一句話:一個運(yùn)行時繼承的方案
所以,啥是裝飾器模式
裝飾器模式的本質(zhì),是通過“包裹”一個已有對象,動態(tài)地給它添加一些行為。這就像給一個人加上一件外套一樣,不改變他本身,但看起來更漂亮或功能更強(qiáng)。用專業(yè)一點(diǎn)的話說,裝飾器模式是一種結(jié)構(gòu)型模式,它允許我們在不改變原有對象結(jié)構(gòu)的基礎(chǔ)上,動態(tài)地添加職責(zé)。
樣板
#include <iostream>
#include <memory>class Component {
public:virtual void operation() const = 0;virtual ~Component() = default;
};class ConcreteComponent : public Component {
public:void operation() const override {std::cout << "ConcreteComponent operation\n";}
};class Decorator : public Component {
protected:std::shared_ptr<Component> component;
public:Decorator(std::shared_ptr<Component> comp) : component(std::move(comp)) {}
};class ConcreteDecoratorA : public Decorator {
public:ConcreteDecoratorA(std::shared_ptr<Component> comp) : Decorator(std::move(comp)) {}void operation() const override {std::cout << "ConcreteDecoratorA adds behavior\n";component->operation();}
};class ConcreteDecoratorB : public Decorator {
public:ConcreteDecoratorB(std::shared_ptr<Component> comp) : Decorator(std::move(comp)) {}void operation() const override {std::cout << "ConcreteDecoratorB adds behavior\n";component->operation();}
};int main() {auto simple = std::make_shared<ConcreteComponent>();auto decorator1 = std::make_shared<ConcreteDecoratorA>(simple);auto decorator2 = std::make_shared<ConcreteDecoratorB>(decorator1);decorator2->operation();return 0;
}
? 如上圖所示,這就是一個最簡單的裝飾器的樣板代碼。我們留心到,我們在構(gòu)造函數(shù)中,動態(tài)的接受基類的指針,現(xiàn)在我們就能擴(kuò)展原先的功能,實(shí)際上上面的decorator2是ConcreteComponent,ConcreteDecoratorA和ConcreteDecoratorB的組合,不信的話試試看上面的代碼?
裝飾器與繼承的對比
裝飾器模式看起來跟繼承很像,因為它也復(fù)用了接口,但它比繼承靈活得多。繼承是編譯期的靜態(tài)行為,你一旦決定了一個類的繼承關(guān)系,就很難在運(yùn)行時修改。而裝飾器是運(yùn)行時的動態(tài)組合,你可以按需添加任意多層功能,不用管組合數(shù)量,也不用寫一堆子類。
應(yīng)用場景總結(jié)
裝飾器模式非常適合用于:
- 不希望修改已有類的前提下添加功能;
- 想要用組合代替繼承,提升靈活性;
- 想對某個對象添加一系列功能(如加邊框、加陰影、加滾動條);
- 希望保持開放封閉原則(對擴(kuò)展開放,對修改封閉);
在圖形界面庫(如 Qt、Java Swing)、流操作(如 C++ 的 iostream
)、Java IO、甚至日志系統(tǒng)中,都可以看到裝飾器模式的身影。
練習(xí)題
基礎(chǔ)裝飾器——文本輸出裝飾器
題目描述:
設(shè)計一個基礎(chǔ)的文本輸出接口 TextPrinter
,默認(rèn)實(shí)現(xiàn)是 PlainTextPrinter
,直接打印字符串?,F(xiàn)在你希望加入一些裝飾器:
QuoteDecorator
:為輸出文本添加前后引號;StarDecorator
:在文本兩邊加上星號***
;UpperCaseDecorator
:將所有輸出內(nèi)容變?yōu)榇髮憽?/li>
要求:
- 使用抽象基類 + 裝飾器類實(shí)現(xiàn);
- 所有裝飾器都可以組合嵌套使用。
提示結(jié)構(gòu):
struct TextPrinter {virtual void print(const std::string& text) = 0;virtual ~TextPrinter() = default;
};class PlainTextPrinter : public TextPrinter {void print(const std::string& text) override;
};class TextDecorator : public TextPrinter {
protected:std::shared_ptr<TextPrinter> wrappee;
public:TextDecorator(std::shared_ptr<TextPrinter> printer);
};class QuoteDecorator : public TextDecorator { ... };
class StarDecorator : public TextDecorator { ... };
class UpperCaseDecorator : public TextDecorator { ... };
實(shí)現(xiàn)的代碼:modern-cpp-patterns-playground/Decorate/TextPrinter at main · Charliechen114514/modern-cpp-patterns-playground