Java的装饰器模式
最近的Lab3中,我使用的是设计方案6,装饰器模式。
每个子类实现不同的特性,因为这些特性都是多个维度上的个性化的特征,没办法做到在一个顶层的接口中完成所有特征的抽象,而且需要做到在各个维度上的特性的任意组合,此时光靠继承是没办法实现特性的组合的,如果要强行使用继承实现,那么面对的一个不可避免地问题是组合爆炸,因为每次继承只能扩展一个特性,多个特性就要多次继承实现,并且也不便于维护与扩展,而且会有大量的重复代码。
因此,提出了Decorator设计模式,为对象增加不同侧面的不同特性。
装饰器模式的原理是从接口派生出子类,然后在子类中定义一个父类接口然后将其作为delegation的对象,也就是说:自己到自己的委派。这里第一个自己指的是子类型本身,第二个自己是指该接口的其他子类,由于他们两个是同一个接口的子类,所以可以称为自己到自己的委派。
可以总结为一下几点:
- 为对象增加不同侧面的特性
- 对每一个特性构造子类,通过委派机制增加到对象上
- 客户端需要一个具有多种特性的object,通过逐层的装饰来实现
下图中,Component是一个接口,接口中是公共的特性,ConcreteComponent是这个接口的基本实现,没有任何个性。Decorator是接口的一个抽象实现,它解决了委派关系的建立问题,从它派生出的诸多子类可以实现各个单独的特性而不必考虑所需要的其他特性如何在本类中实现,这些问题都通过delegation机制交给了其他子类完成。
//Stack接口,定义了所有的Stack共性的基础的功能
interface Stack {
void push(Item e);
Item pop();
}
//最基础的类,啥个性也没有的Stack,只有共性的实现
public class ArrayStack implements Stack {
... //rep
public ArrayStack() {...}
public void push(Item e) {...}
public Item pop() { ... }
}
//装饰器类,可以是一个抽象类,用于扩展出有各个特性方面的各个子类
public abstract class StackDecorator implements Stack {
protected final Stack stack; //用来保存delegation关系的rep
public StackDecorator(Stack stack) {
this.stack = stack; //建立稳定的delegation关系
}
public void push(Item e) {
stack.push(e); //通过delegation完成任务
}
public Item pop() {
return stack.pop(); //通过delegation完成任务
}
}
//一个有撤销特性功能的子类
public class UndoStack extends StackDecorator implements Stack {
private final UndoLog log = new UndoLog();
public UndoStack(Stack stack) {
super(stack); //调用父类的构造方法建立delegation关系
}
public void push(Item e) {
log.append(UndoLog.PUSH, e); //实现个性化的功能
super.push(e); //共性的功能通过调用父类的实现来完成
}
public void undo() {
//implement decorator behaviors on stack
}
...
}
我们使用装饰类,通过一层一层地装饰,让各有特点的对象能够拥有不同特性,其实就是针对各类的共性和特性进行不同层次的设计,进行方法的复用和重写。
// 先创建出一个基础类对象
Stack s = new ArrayStack();
// 利用UndoStack中继承到的自己到自己的委派建立起从UndoStack到ArrayStack的delegation关系
// 这样,UndoStack也就能够实现最基础的功能,并且自身也实现了个性化的功能
Stack us = new UndoStack(s);
// 通过一层层的装饰实现各个维度的不同功能
Stack ss = new SecureStack(new SynchronizedStack(us));