图解设计模式--Decorator(装饰者)模式

装饰边框与被装饰物的一致性

Decorator 模式

不断地为对象添加装饰的设计模式被称为 Decorator 模式。

示例程序

名字 说明 类型
Display 用于显示字符串的抽象类 Component
StringDisplay 用于显示单行字符串的类 ConcreteComponent
Border 用于显示装饰边框的抽象类 Decorator
SideBorder 用于只显示左右边框的类 ConcreteDecorator
FullBorder 用于显示上下左右边框的类 ConcreteDecorator
Main 测试程序行为的类

Display.java

package decorator;

public abstract class Display {
    public abstract int getColumns();
    public abstract int getRows();
    public abstract String getRowText(int row);
    public final void show() {
        for (int i = 0 ; i < getRows(); i++) {
            System.out.println(getRowText(i));
        }
    }
}

StringDisplay.java

package decorator;

public class StringDisplay extends Display {
    private String string;
    public StringDisplay(String string) {
        this.string = string;
    }
    public int getColumns() {
        return string.getBytes().length;
    }
    public int getRows() {
        return 1;
    }
    public String getRowText(int row) {
        if (row == 0) {
            return string;
        } else {
            return null;
        }
    }
}

Border.java

package decorator;

public abstract class Border extends Display {
    protected Display display;
    protected Border(Display display) {
        this.display = display;
    }
}

SideBorder.java

package decorator;

public class SideBorder extends Border {
    private char borderChar;
    public SideBorder(Display display, char ch) {
        super(display);
        this.borderChar = ch;
    }
    public int getColumns() {
        return 1 + display.getColumns() + 1;
    }
    public int getRows() {
        return display.getRows();
    }

    public String getRowText(int row) {
        return borderChar + display.getRowText(row) + borderChar;
    }
}

FullBorder.java

package decorator;

public class FullBorder extends Border {
    public FullBorder(Display display) {
        super(display);
    }

    public int getColumns() {
        return 1 + display.getColumns() + 1;
    }

    public int getRows() {
        return 1 + display.getRows() + 1;
    }

    public String getRowText(int row) {
        if (row == 0) {
            return "+" + makeLine('-', display.getColumns()) + "+";
        } else if (row == display.getRows() + 1) {
            return "+" + makeLine('-', display.getColumns()) + "+";
        } else {
            return "|" + display.getRowText(row - 1) + "|";
        }
    }

    private String makeLine(char ch, int count) {
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < count; i++) {
            buf.append(ch);
        }
        return buf.toString();
    }
}

Main.java

package decorator;

public class Main {
    public static void main(String[] args) {
        Display b1 = new StringDisplay("Hello, world.");
        Display b2 = new SideBorder(b1, '#');
        Display b3 = new FullBorder(b2);
        b1.show();
        b2.show();
        b3.show();
        Display b4 = new SideBorder(
                new FullBorder(
                        new FullBorder(
                                new SideBorder(
                                        new FullBorder(
                                                new StringDisplay("你好,世界。")
                                        ),
                                        '*'
                                )
                        )
                ),
                '/'
        );
        b4.show();
    }
}

Decorator 模式中的角色

  1. Component

    增加功能时的核心角色。被装饰的角色。

  2. ConcreteComponent

    该角色实现了 Component 角色所定义的接口。

  3. Decorator(装饰物)

    该角色具有与 Component 角色相同的接口。在它内部保存了被装饰对象--Component角色。

  4. ConcreteDecorator(具体的装饰物)

    该角色是具体的Decorator。

拓展思路

一、接口的透明性。装饰物是被装饰物的子类,这就体现了他们之间的一致性。这样被装饰物和装饰物就有相同的接口。

二、优点是在不改变被装饰物的前提下可以增加功能。只需要加装饰物就可以添加功能。

三、缺点是,会导致程序中增加许多功能类似的很小的类。

推荐阅读更多精彩内容