两种结构型设计模式
本文介绍了两种结构型设计模式——适配器模式和装饰器模式。
适配器模式
适配器模式就是用另一个类作为“适配器”,将原来的类的操作转换成用户需要的形式。用户只需要和这个“适配器”打交道,而不需要和原来的类打交道,“适配器”通过委托(也就是说,原来的类作为“适配器”的属性)调用原来的类的方法完成任务。
对于:
class LegacyRectangle {
void display(int x1, int y1, int w, int h) {...}
}
class Client {
public display() {
new LegacyRectangle().display(x1, y1, x2, y2);
}
}
增加“适配器”:
class Rectangle{
LegacyRectangle rectangle = new LegacyRectangle();
void display(int x1, int y1, int x2, int y2) {
rectangle.display(x1, y1, x2, y2);
}
}
class LegacyRectangle implements Shape{
void display(int x1, int y1, int w, int h) {...}
}
class Client {
public display() {
Rectangle rectangle = new Rectangle();
rectangle.display(x1, y1, x2, y2);
}
}
现在用户跟LegacyRectangle
就被Rectangle
**”适配“**了,用户只需要使用Rectangle
里的操作即可。
装饰器模式
我们知道如果想要给一个ADT增加特性的话,我们可以写一个子类,重写父类中的方法。这样的确可以增加特性,但是如果我们想要将这些特性组合起来,我们就会遇到问题。
因为这些子类相互之间没有关系,我们不得不为这些子类再增加子类来实现特性的组合。随着特性的增多,可能我们还得实现子类的子类的子类,以及子类的子类的子类的子类,这就会产生组合爆炸的问题。
装饰器模式正是用来解决这个问题的。它将不同的特性通过层层嵌套的方法组合起来,而不需要额外的代码。
对于:
interface Stack{
void push(Item e);
Item pop();
}
public ArrayStack implements Stack{
public ArrayStack(){...}
public void push(Item e){...}
public Item pop(){...}
}
我们实现一个通用的装饰器抽象类:
public abstract class StackDecorator implements Stack {
protected final Stack stack;
public StackDecorator(Stack stack) {
this.stack = stack;
}
public void push(Item e) {
stack.push(e);
}
public Item pop() {
return stack.pop();
}
}
然后实现一个用于加装特性的装饰器具体类:
public UndoStack extends StackDecorator implements Stack {
private final UndoLog log = new UndoLog();
public UndoStack(Stack stack) {
super(stack);
}
public void push(Item e) {
log.append(UndoLog.PUSH, e);
super.push(e);
}
public void undo() {
...
}
...
}
当我们想使用加装了特性的Stack
的时候,我们可以:
Stack t = new UndoStack(new ArrayStack());
装饰器模式最大的特点是将Stack
作为构造方法的参数,赋给内部的属性,对这个属性进行复用。这个Stack
不仅可以是通用的ArrayStack
,它可以是任何Stack
,也就可以是加装了特性后的Stack
,例如UndoStack
,从而实现了特性组合的方法——层层嵌套。
如果我们再定义两个装饰器具体类:
public SynchronizedStack extends StackDecorator implements Stack {...}
public SecureStack extends StackDecorator implements Stack {...}
我们就可以这样将它们组合起来:
Stack s = new SecureStack(new SynchronizedStack(new UndoStack(new ArrayStack())));
可以看到我们使用层层嵌套实现了特性的组合,不需要多余的代码,没有产生组合爆炸。