Decorator 模式
不断地为对象添加装饰的设计模式被称为Decorator 模式。
示例程序类图
示例程序
Display
public abstract class Display {
public abstract int getColumns(); // 获取横向字符数
public abstract int getRows(); // 获取纵向行数
public abstract String getRowText(int row); // 获取第row行的字符串
public void show() { // 全部显示
for (int i = 0; i < getRows(); i++) {
System.out.println(getRowText(i));
}
}
}
StringDisplay
public class StringDisplay extends Display {
private String string; // 要显示的字符串
public StringDisplay(String string) { // 通过参数传入要显示的字符串
this.string = string;
}
@Override
public int getColumns() { // 字符数
return string.getBytes().length;
}
@Override
public int getRows() { // 行数是1
return 1;
}
@Override
public String getRowText(int row) { // 仅当row为0时返回值
if (row == 0) {
return string;
} else {
return null;
}
}
}
Border
public abstract class Border extends Display {
protected Display display; // 表示被装饰物
protected Border(Display display) { // 在生成实例时通过参数指定被装饰物
this.display = display;
}
}
SideBorder
public class SideBorder extends Border {
private char borderChar; // 表示装饰边框的字符
public SideBorder(Display display, char ch) { // 通过构造函数指定Display和装饰边框字符
super(display);
this.borderChar = ch;
}
@Override
public int getColumns() { // 字符数为字符串字符数加上两侧边框字符数
return 1 + display.getColumns() + 1;
}
@Override
public int getRows() { // 行数即被装饰物的行数
return display.getRows();
}
@Override
public String getRowText(int row) { // 指定的那一行的字符串为被装饰物的字符串加上两侧的边框的字符
return borderChar + display.getRowText(row) + borderChar;
}
}
FullBorder
public class FullBorder extends Border {
public FullBorder(Display display) {
super(display);
}
@Override
public int getColumns() { // 字符数为被装饰物的字符数加上两侧边框字符数
return 1 + display.getColumns() + 1;
}
@Override
public int getRows() { // 行数为被装饰物的行数加上上下边框的行数
return 1 + display.getRows() + 1;
}
@Override
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) { // 生成一个重复count次字符ch的字符串
StringBuffer buf = new StringBuffer();
for (int i = 0; i < count; i++) {
buf.append(ch);
}
return buf.toString();
}
}
Main
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
增加功能时的核心角色。在示例程序中,由Display类扮演此角色。
2.ConcreteComponent
该角色是实现了Component角色所定义的接口(API)的具体蛋糕。在示例程序中,由StringDisplay类扮演此角色。
3.Decorator(装饰物)
该角色具有与Component角色相同的接口(API)。在它内部保存了被装饰对象——Component角色。Decorator角色知道自己要装饰的对象。在示例程序中,由Border类扮演此角色。
4.ConcreteDecorator(具体的装饰物)
该角色是具体的Decorator角色。在示例程序中,由SideBorder和FullBorder类扮演此角色。
通用类图
Decorator 模式的主要目的是通过添加装饰物来增加对象的功能。
继承和委托中的一致性
public class Parent {
void parentMethod(){
System.out.println("Parent");
}
}
public class Child extends Parent {
private String namec = "child";
void childMethod() {
System.out.println("Child");
}
public static void main(String[] args) {
// 输出Parent,parent
Parent obj = new Child();
obj.parentMethod();
System.out.println(obj.name);
// 输出Child
Parent obj1 = new Child();
((Child) obj1).childMethod();
}
}
从上面的代码中,我们可以看到Child类的实例可以被保存在Parent类型的变量中,也可以调用从Parent类中继承的方法。
我们可以像操作Parent类的实例一样操作Child类的实例。这是将子类当作父类看待的一个例子。
但是反过来,如果想将父类当作子类一样操作,则需要先进行类型转换。