组成
结构型模式涉及到如何组合类和对象,以获得更大的结构,更丰富的功能。主要有"类继承、对象组合"两种方式,
装饰器模式(Decorator)可以动态地给对象添加一些额外的功能,比如有时我们希望给某个对象而不是整个类添加一些功能,那么就可以用装饰器模式,把目标对象嵌入到装饰器对象中。
装饰器模式的组成如下:
Component:一个接口对象
ConcreteComponent:Component 的具体实现类
Decorator:装饰器接口,维持一个指向 Component 对象的引用,必须继承自 Component 接口
ConcreteDecorator:装饰器的具体实现类,用于向 Component 对象添加职责
Decorator 将请求转发给它的 Component 对象,并有可能在转发请求前后执行一些附加的动作。
应用场景
1、希望给某个对象增加功能,而不是整个类,不会影响这个类其他对象。
2、继承不利于系统维护,甚至不能使用继承关系的场景。
3、需要动态、透明的给对象添加或撤销功能。
示例代码
Java 类库中 Collections 就有一个很典型的装饰器模式实现:Collecitons.SynchronizedList()。
java
List<String> list = Collections.synchronizedList(new ArrayList<>());
该方法可以把非线程安全的 List 对象包装成线程安全的 List 对象返回,很符合"给某个对象增加功能,但不影响整个类"的要求。
改方法的内部实现,是使用一个新的类 SynchronizedList
作为装饰器,包装了传入的 List 对象,该类的定义如下:
java
static class SynchronizedList<E> extends SynchronizedCollection<E> implements List<E> {
private static final long serialVersionUID = -7754090372962971524L;
final List<E> list;
SynchronizedList(List<E> list) {
super(list);
this.list = list;
}
SynchronizedList(List<E> list, Object mutex) {
super(list, mutex);
this.list = list;
}
public E get(int index) {
synchronized (mutex) {return list.get(index);}
}
}
可以看到,这个装饰器类自身也继承了它要装饰的 Component (List 接口),并实现了 List 的方法,在调用时,会使用 synchroinzed 加锁,在转发给被装饰的对象 list,让 list 的方法变得线程安全。
优点和缺点
优点
1、比继承更加灵活
使用装饰器可以在需要的时候给某个对象增加功能,而不是使用继承,让所有子类对象都被增强。
2、简单、即用即付
不需要在一个装饰器类中定义所有需要增强的功能,而是可以定义多个简单的装饰器类,逐个调用,逐渐给 component 添加功能,从简单的部件组合出复杂的功能。
缺点
1、Decorator 和 Compnent 不一样
虽然 Decorator 继承了 Compnent 接口,但实际上同名方法和 Compnent 还是有差异的,不能把 Decorator 当做 Compnent 使用。
2、会产生很多装饰器类
如果要添加的功能很多,会创建很多相似的装饰器类和对象,使的维护和排查更加困难。
小结
装饰器模式可以在不改变 Compnent 实现的前提下,给 Compnent 对象增加功能,并且可以保持 Compnent 的简单性。
Decorator 类似对象的外壳,通过一层层的嵌套,动态地给对象添加功能。