音乐播放器
scraty's Blog
 
文章 标签
9

Powered by Gridea | Theme: Fog

两种结构型设计模式

本文介绍了两种结构型设计模式——适配器模式和装饰器模式。

适配器模式

适配器模式就是用另一个类作为“适配器”,将原来的类的操作转换成用户需要的形式。用户只需要和这个“适配器”打交道,而不需要和原来的类打交道,“适配器”通过委托(也就是说,原来的类作为“适配器”的属性)调用原来的类的方法完成任务。

对于:

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())));

可以看到我们使用层层嵌套实现了特性的组合,不需要多余的代码,没有产生组合爆炸。