该文章是阅读《图解设计模式》的学习笔记。书本链接https://www.ituring.com.cn/book/1811
如现在有几块方形面包,你可以加入火腿鸡蛋并切成三角形状做成一个三明治;或者加入火腿牛肉块芝士并切成原型形状做成一个汉堡包。但无论你是制作三明治还是汉堡包,它的核心都是方形面包,只是加上了牛肉块火腿鸡蛋芝士这些材料进行装饰,让面包变得更美味。我们也可以采用这种思想进行编程,一个相当于方形面包的对象,然后不断编写代码引入新功能装饰这个对象,让该对象的功能变得更具体,变成一个更加明确的对象。像这种不断为对象添加装饰的模式被称为Decorator(装饰物)模式。
Display抽象类代码:
package com.wen.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类代码:
package com.wen.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));
}
}
}
Border抽象类代码:
package com.wen.Decorator;
public abstract class Border extends Display{
protected Display display;
protected Border(Display display){
this.display = display;
}
}
SideBorder类代码:
package com.wen.Decorator;
public class SideBorder extends Border {
private char borderChar;
public SideBorder(Display display, char borderChar) {
super(display);
this.borderChar = borderChar;
}
@Override
public int getColumns() {
return display.getColumns()+2;//有左右两边所以列数加2
}
@Override
public int getRows() {
return display.getRows();
}
@Override
public String getRowText(int row) {
return borderChar+display.getRowText(row)+borderChar;//拼合两边的字符组成字符串
}
}
FullBorder类代码:
package com.wen.Decorator;
public class FullBorder extends Border {
public FullBorder(Display display) {
super(display);
}
public int getColumns() { //左右边界加两列
return display.getColumns() + 2;
}
public int getRows() { //上下边界加两行
return display.getRows()+2;
}
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入口类代码:
package com.wen.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();
}
}
模式中的角色:
Component(组件):增加功能时的核心角色,以上面的代码为例Display属于该角色。里面定义了显示字符串所需的方法。
ConcreteComponent(具体的组件):负责实现组件类定义的接口,上边代码中StringDisplay负责显示字符串的类代码此角色。
Decorator(装饰物):该角色内部包含了被装饰的Component组件角色,并具有与Component角色相同的方法。
ConcreteDecorator(具体的装饰物):负责实现Decorator角色定义的装饰方法。