1、意图
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式(Decorator)相比生成子类更为灵活。
2、结构
3、参与者
Component:定义一个对象接口,可以给这些对象动态地添加职责。
ConcreteComponent:定义一个对象,可以给这个对象添加一些职责。
Decorator:维持一个指向Component对象的指针,并定义一个与Component接口一直的接口。
ConcreteDecorator:向组件添加职责。
4、适用性
以下情况使用装饰模式:
在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责;
处理那些可以撤销的职责;
当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况是因为类定义被隐藏,或类定义不能用于生成子类;
5、代码示例
class visualComponent { public: visualComponent(); virtual void Draw(); virtual void Resize(); }; // 定义VisualComponent的一个子类Decorator,我们将生成Decorator的子类以获取不同的装饰。 class Decorator : public visualComponent { public: Decorator(visualComponent*); virtual void Draw(); virtual void Resize(); // ... private: visualComponent* _component; }; // Decorator装饰由_component实例变量引用的VisualComponent,这个实例变量在构造器中被初始化。 // 对于VisualComponent接口中定义的每一个操作,Decorator类都定义了一个缺省的实现,这一实现将请求转发给_component: void Decorator::Draw () { _component->Draw (); } void Decorator::Resize () { _component->Resize(); }
// Decorator的子类定义了特殊的装饰功能,例如,BorderDecorator类为它所包含的组件添加了一个边框。 // BorderDecorator是Decoratorl的子类,它重定义Draw操作用于绘制边框。同时BorderDecorator还定义了 // 一个私有的辅助操作DrawBorder,由它绘制边框。这些子类继承了Decorator类所有其他的操作。 class BorderDecorator : public Decorator { public: BorderDecorator(VisualComponent*, int borderwidth); virtual void Draw(); private: void DrawBorder(int); private: int_width; }; void BorderDecorator::Draw () { Decorator::Draw(); DrawBorder(_width); } // 类似的可以实现ScrollDecorator和DropShadowDecorator,它们给可视组件添加滚动和阴影功能。
// 将一个可视组件放入窗口对象中 void Window::SetContents (VisualComponent* contents) { // ... } // 现在我们可以创建一个正文视图以及放入这个正文视图的窗口: Window* window = new Window; Textview* textview = new Textview; // TextView是一个VisualComponent,它可以放入窗口中: window->SetContents(textview); // 但我们想要一个有边界的和可以滚动的TextView,因此我们在将它放入窗口之前对其进行装饰: window->SetContents(new BorderDecorator(new ScrollDecorator(textview),1);
6、总结
装饰模式用来代替子类生成方式,动态地给一个对象添加一些额外职责。装饰模式的目的是解决主体类在多个方向上拓展的问题。
装饰模式可以比继承方式更加灵活地拓展功能。通过不同具体装饰类进行排列组合,可以创造出很多不同行为的组合。
使用装饰模式,比使用继承方式需要的类的数目更少。但,使用装饰模式会比使用继承方式产生更多的对象。
装饰模式中,Decorator类对Component类透明,Decorator用来拓展Component类的功能,Decorator必须与Component的接口一致,对于用户来说就是统一的接口。
组件ConcreteComponent和装饰Decorator均继承自Component,为保证接口一致性,Component的实现需尽量地简单。