diff --git a/10_decorator.cpp b/10_decorator.cpp new file mode 100644 index 0000000..0ee08a4 --- /dev/null +++ b/10_decorator.cpp @@ -0,0 +1,51 @@ +#include +#include + +using namespace std; + +class Coffee { +public: + virtual void make() = 0; + virtual ~Coffee() = default; +}; + + +class SimpleCoffee : public Coffee { +public: + virtual void make() override { + cout << "Coffee"; + } +}; + +class MilkDecorator : public Coffee { + unique_ptr coffee; +public: + MilkDecorator(unique_ptr c) : coffee(move(c)) { + } + virtual void make() override { + coffee->make(); + cout << " + Milk"; + } +}; + + +class SugarDecorator: public Coffee { + unique_ptr coffee; +public: + SugarDecorator(unique_ptr c) : coffee(move(c)) { + } + virtual void make() override { + coffee->make(); + cout << " + Sugar"; + } +}; + + +int main() { + auto coffee = make_unique(); + auto milk_coffee = make_unique(move(coffee)); + auto sugar_coffee = make_unique(move(milk_coffee)); + + sugar_coffee->make(); + cout << endl; +} diff --git a/notes.md b/notes.md index 61dc3e8..392a020 100644 --- a/notes.md +++ b/notes.md @@ -66,3 +66,8 @@ 组合模式正是为了解决这个问题。它的核心思想是:将对象组合成树形结构来表示“整体-部分”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。也就是说,我们可以将一个组件(由多个元素组成)当作一个普通元素一样来处理,统一操作接口,简化客户端代码。 +## 装饰器模式(Decorator) + +有时,我们需要给动态的一个类添加一些组件。例如:对于制作一杯咖啡,可以添加牛奶,糖等。一种做法是使用继承,这显然会造成类爆炸。另一种做法是将这些配料抽象成一个类,咖啡类维护一个配料的列表。对于纯数据,如计算最终价格,这样是合理的。但是对于添加额外行为,这就会将逻辑集中到 Coffee 类中。例如希望添加牛奶时咖啡必须加热,就不得不修改 Coffee 类,在它的 make 函数中添加处理逻辑。 + +装饰器模式解决了这个问题。让所有的配料都继承自 Coffee,构建时则额外需要一个被装饰对象的指针,构造函数中还能插入额外的处理。这样可以让每一层都能主动拦截、加工、改写行为,而不需要集中到一个地方。对于客户端代码来说,装饰器和原对象是一样的。当需要对咖啡做某个动作时,可以对装饰器做,装饰器再调用被修饰对象指针的对应动作。由于包含关系,装饰器还天然记录了顺序。