• 维基百科:https://en.wikipedia.org/wiki/Decorator_patternios
GoF:Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
GoF:该模式能够动态地为一个对象附加上额外的职责。装饰器为扩展功能的子类化行为提供一个灵活的替换方案。
设计模式
Wikipedia:In object-oriented programming, the decorator pattern (also known as Wrapper, an alternative naming shared with the Adapter pattern) is a design pattern that allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class. The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern.app
Wikipedia:在面向对象编程中,装饰器模式(一般也称为包装器模式,这种叫法也被在适配器模式中使用)是一种为一个单独的对象静态或动态地添加对象行为,同时不影响同类生成的其余对象的行为的设计模式。装饰器模式一般在遵循单一责任原则的设计中十分有用,这是因为它容许功能在两个类之间进行拆分。ide
百度百科:23种设计模式之一,英文叫Decorator Pattern,又叫装饰者模式。装饰模式是在没必要改变原类文件和使用继承的状况下,动态地扩展一个对象的功能。它是经过建立一个包装对象,也就是装饰来包裹真实的对象。函数
Decorator设计模式能够用于静态地扩展一个特定对象的功能,或者在某些场景能够在运行期扩展一个特定对象的功能,而不影响与该对象的同类型(同一个类)的其余对象。Decorator模式能够在不改变原类文件和使用继承的状况下,动态地扩展一个对象的功能。它是经过建立一个包装对象,也就是装饰来包裹真实的对象。flex
GoF:Defines the interface for objects that can have responsibilities added to them dynamically.编码
为真实对象定义能够动态添加功能的接口。url
GoF:Defines an object to which additional responsibilities can be attached.spa
定义一个能够附加额外功能的对象类型。
GoF:Maintains a reference to a Component object and defines an interface that conforms to Component's interface.
维护一个指向Component对象的引用,而且定义和Component一致的接口。
GoF:Adds responsibilities to the component.
为Component添加具体的功能。
• 装饰对象和真实对象具备相同的接口,这样用户对象就能以与真实对象交互的相同方式和装饰对象交互。
• 装饰对象包含一个真实对象的引用。
• 装饰对象接受来自用户对象的请求,并把这些请求转发给真实的对象。
• 在同一个真实对象之上能够堆叠多个装饰对象,每次堆叠能够为重写函数添加新的功能点。所以咱们能够一条终于原对象的装饰对象链。
在我看来,装饰器模式迷人之处在于能够为一个对象造成一个装饰器链,该装饰器链上每个结点只负责本身“装饰”的功能点。这种特色使得咱们能够不断调整一个对象的职能,能够任意地添加和删除所需的功能。可以这样实现装饰器链的缘由很简单,不管是具体的Component仍是具体的Decorator,都重写了规约接口operation;而且Decorator和Component是处于同一继承体系之中,咱们能够将Decorator视为是一种特殊的Component,但实际上继承只是为了多态的性质,即只须要持有Component类型的一个reference,而无所谓这个reference是引用具体的Component仍是Decorator,都可以正确调用具体的operation接口。
在实际使用中,咱们常常能够看到1级装饰器D1中持有实际对象引用,2级装饰器D2中持有装饰器D1对象引用,以此类推。
如下面例子一的状况,咱们能够编码以下:
#include <string> #include <iostream> using namespace std; // Window class Window { public: Window() {} virtual ~Window() {} public: virtual void Draw() = 0; virtual string GetDescription() = 0; }; // SimpleWindow class SimpleWindow : public Window { public: SimpleWindow() {} virtual ~SimpleWindow() {} public: virtual void Draw() { cout << "SimpleWindow::Draw()" << endl; } virtual string GetDescription() { return "Simple Window"; } }; // WindowDecorator class WindowDecorator : public Window { protected: Window &m_rWindowToBeDecorated; public: WindowDecorator(Window &rWindowToBeDecorated) : m_rWindowToBeDecorated(rWindowToBeDecorated) {} virtual ~WindowDecorator() {} public: virtual void Draw() { m_rWindowToBeDecorated.Draw(); } virtual string GetDescription() { return m_rWindowToBeDecorated.GetDescription(); } }; // VerticalScrollBarDecorator class VerticalScrollBarDecorator : public WindowDecorator { public: VerticalScrollBarDecorator(Window &rWindowToBeDecorated) : WindowDecorator(rWindowToBeDecorated) {} virtual ~VerticalScrollBarDecorator() {} public: virtual void Draw() { WindowDecorator::Draw(); DrawVerticalScrollBar(); } virtual string GetDescription() { return WindowDecorator::GetDescription() + ", including vertical scrollbars"; } private: void DrawVerticalScrollBar() { cout << "VerticalScrollBarDecorator::DrawVerticalScrollBar()" << endl; } }; class HorizontalScrollBarDecorator : public WindowDecorator { public: HorizontalScrollBarDecorator(Window &rWindowToBeDecorated) : WindowDecorator(rWindowToBeDecorated) {} virtual ~HorizontalScrollBarDecorator() {} public: virtual void Draw() { WindowDecorator::Draw(); DrawHorizontalScrollBar(); } virtual string GetDescription() { return WindowDecorator::GetDescription() + ", including horizontal scrollbars"; } private: void DrawHorizontalScrollBar() { cout << "HorizontalScrollBarDecorator::DrawHorizontalScrollBar()" << endl; } }; int main() { SimpleWindow window; VerticalScrollBarDecorator decorated1(window); HorizontalScrollBarDecorator decorated2(decorated1); decorated2.Draw(); cout << decorated2.GetDescription() << endl; return 1; }
输出结果为:
这个例子出自于Wikipedia:https://en.wikipedia.org/wiki/Decorator_pattern
以一个窗口系统中的窗口为例。为了可以使窗口内容进行滚动显示,用户可能但愿在窗口中添加垂直或水平方向上的滚动条控件来实现功能。假设全部窗口都由Window这个类实例来显示,而且初始Window类并无添加滚动条的功能。一种作法能够建立ScrollingWindow子类来提供带滚动条的窗口,另外一种作法是建立一个ScrollingWindowDecorator装饰器来为已有的Window类实例来实现功能。到目前为止,两种解决方案都是可行的。
假设用户同时也但愿窗口中能增长边框显示的功能,而且初始Window类并无支持。ScrollingWindow窗口类此时就产生了问题,由于它其实是建立了一个新的窗口类型。若是用户但愿给大多数窗口增长边框显示,而不是全部窗口,那么咱们势必须要建立相似WindowWithBorder和ScrollingWindowWithBorder等的窗口类。这个问题在每增长一种新的窗口特效或窗口类型时会变得更加糟糕。若是使用装饰器的解决方案,咱们只须要简单地在运行期建立一个新的BorderedWindowDecorator装饰器便可,那么咱们可使用ScrollingWindowDecorator和BorderedWindowDecorator装饰器来装饰已有的窗口实例。若是用户但愿一个功能能被全部窗口所使用,那么咱们修改基类Window来实现,反之,修改基类有时是没有可能的,或不合法的,或不方便的行为。
这个例子出自于GoF,与Wikipedia的例子十分相似。
例如,假设咱们拥有一个TextView控件来在窗口中显示文本,在默认状况下,TextView控件是没有滚动功能的,由于用户并非一直都须要文本滚动功能。当须要为TextView实例增长文本滚动功能,咱们只须要使用ScrollDecorator装饰器来增添功能。假设咱们须要为TextView控件加上一个粗的黑色边框来装饰控件,那么咱们要作的也只是使用BorderDecorator装饰器来实现。在这种思路下,咱们只须要简单地在TextView对象上组合各类装饰器,就能产生咱们所须要的结果。
下面的对象关系图显示了怎样在TextView对象上组合使用BorderDecorator和ScrollDecorator装饰器对象来产生一个带边框和滚动条的文本视图: