动态的给一个对象增加一些额外的职责。 对于增加功能来说,Decorator模式比生成子类更为灵活。
使用继承是添加功能的一种有效途径,从其他类继承过来的特性可以被多个子类实例使用。但是这种方法不够灵活,用户不能控制对新功能增加的方式和时机。
一种灵活的方式是将要扩展的组件对象嵌入到另外一个对象中,由这个对象负责新的功能。这个嵌入对象就是装饰。 装饰的接口与要扩展的组件接口一致,以对用户透明。装饰通过包含组件本身,以转发调用,以便于扩展。
使用情况:
1 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加功能。
2 处理那些可以撤销的职责。
3 当不能采用生成子类方式进行扩充时。 一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目称爆炸式增长。另外的可能是类定义被隐藏,或类不能用于生成子类。
参与者:
Component: 定义对象接口。要扩展功能的对象。
ConcreteComponet 定义对象,可以给对象增加职责。
Decorator 包含了指向Component对象的指针,并定义与Component接口一致的接口。
ConcreteDecorator 扩展新的功能
示例:
class VisualComponent {
public:
Visualcomponent();
virtual void Draw();
virtual void Resize();
};
class TextView : public VirsualComponent {
};
class Decorator : public VisualComponent {
public:
Decorator(Visualcomponent *);
virtual void Draw() {
_component->Draw();
}
virtual void Resize();
private:
Visualcomponent* _component;
};
class BorderDecorator : public Decorator {
public:
BorderDecorator(Visualcomponent*);
virtual void Draw() {
DrawBorder();
_component->Draw();
}
private:
void DrawBorder();
};
在使用时:
Window *w = new Window();
TexView * tv = new TexView();
w->setcontex(tv);
当我们要扩展时:
w->setcontex(new BorderDecorator (
new ScrollDecorator(tv))
);
这样避免了定义一个新的子类,通过多重继承TexView BorderDecorator ScrollDecoratorl来达到相同的效果。并且具有更大的灵活性,可扩展。
Decorator的优点缺点:
1 比静态继承更加灵活 与对象的静态继承、多重继承相比,Decorator更加灵活的扩展方式。 用装饰运行时增加和删除功能。 继承机制则会产生很多子类。
2 避免在层次结构高层的类有太多的特征 Decorator并不给一个复杂可定制的类中支持所有可预见的特征。可以从简单的部件复合出复杂的功能。并且也不依赖于Decorator进行的扩展。
3 Decorator与Component不同 Decorator是透明的包装。使用装饰时,不应该依赖对象标识。
4 有许多小对象 使用Decorator会产生看上去类似小对象,这些对象仅仅在他们相互连接的方式伤不同。而不是他们的类或者属性值不同。 对于熟悉系统的人很容易定制,但是很难学习这些系统,排错困难。
实现时,注意的点:
1 接口一致性 装饰对象接口必须与它所装饰的Component接口一致。 所有的ConcreteDecorator都有公共的父类。
2 省略抽象的Decorator类 当仅需要增加一个功能时,不需要定义抽象的Decorator。
3 保持Component的简单性 为了保证接口的一直,Decorator和组件必须要有公共的Component父类。父类应当集中定义接口,而不是存储数据。
4 改变对象外壳与改变对象内核 可以将Decorator看做一个对象的外壳,可以改变对象的行为。另外一种方法是改变对象的内核。 例如Strategy就是改变内核。
当Component类原本就很大时,使用Decorator代价太高。Strategy效果会更好。