意图
动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。
例子
最好的例子就是ui图,在针对富文本进行编辑的时候,工具栏、文本栏、保存/取消栏等,都是是在其基础上进行装饰的效果。
首先是基础绘图组件public interface VisualComponent {
public void draw();
}
以及具备该功能抽象类pubic class abstract Decorator implements VisualComponet {
VisualComponent component;
void draw() {
component.draw();
}
}
接下来就可以使用抽象类的子类完成工作public class BorderDecorator extends Decorator {
public BorderDecorator(VIsualComponent component) {
this.component = component;
}
void drawBorder() {
// TODO...
}
void draw() {
super.draw();
drawBorder();
}
}
这样在原有的基础draw上,增加了其他的操作。一层嵌套一层形成新的子类,并在原有基础上更具有针对性增加功能。
适用性
- 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
- 处理那些可能撤销的职责
- 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
结构
协作
Decorator 将请求转发给它的 Component 对象,并有可能在转发请求前后执行一些附加的动作。
效果
Decorator 模式至少有两个主要优点和两个缺点:
- 比静态继承更灵活
与对象的静态继承(多重继承)相比,Decorator模式提供了更加灵活的向对象添加职责的方式。可以用添加和分离的方法,用装饰在运行时刻增加和删除职责。相比之下,继承机制要求为每个添加的职责创建一个新的子类(例如,BorderScrollableTextView, BorderedTextView)。这会产生许多新的类,并且会增加系统的复杂度。此外,为一 个特定的Component类提供多个不同的Decorator类,这就使得你可以对一些职责进行混合和匹配。
使用 Decorator 模式可以很容易地重复添加一个特性,例如在 TextView 上添加双边框时, 仅需将添加两个 BorderDecorator 即可。而两次继承 Border 类则极容易出错的。 - 避免在层次结构高层的类有太多的特征
Decorator模式提供了一种“即用即付”的方法来添加职责。它并不试图在一个复杂的可定制的类中支持所有可预见的特征,相反,你可以定义一个简单的类,并且用Decorator类给它逐渐地添加功能。可以从简单的部件组合出复杂的功能。这样,应用程序不必为不需要的特征付出代价。同时也更易于不依赖于 Decorator 所扩展(甚至是不可预知的扩展)的类而独立地定义新类型的Decorator。扩展一个复杂类的时候,很可能会暴露与添加的职责无关的细节。 - Decorator 与它的 Component 不一样
Decorator是一个透明的包装。如果我们从对象标识的观点出发,一个被装饰了的组件与这个组件是有差别的,因此,使用装饰时不应该依赖对象标识。 - 有许多小对象
采用Decorator模式进行系统设计往往会产生许多看上去类似的小对象,这些对象仅仅在他们相互连接的方式上有所不同,而不是它们的类或是它们的属性值有所不同。尽管对于那些了解这些系统的人来说,很容易对它们进行定制,但是很难学习这些系统,排错也很困难。