1、引入
说起装饰,我第一时间想到的是节日里给礼物的层层包装。
而装饰模式,就是提供特定的几个装饰器,不断给被装饰品添上一层层装饰,以实现丰富的外观形态。
而能够不断被装饰,需要装饰的“边框”与被装饰物具有一致性,使得被装上边框后还能够作为装饰物为其他边框所装饰。
2、示例
实现功能:能够为字符串不断添加各类边框,形成复杂的结构
2.1、装饰边框与被装饰物的统一父类Dispaly
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));
}
}
}
2.2、字符串展示StringDislay类
public class StringDisplay extends Display{
private String string;
public StringDisplay(String string) {
this.string = string;
}
@Override
public int getColumns() {
return string.length();
}
@Override
public int getRows() {
return 1;
}
@Override
public String getRowText(int row) {
if (row == 0) {
return string;
} else {
return null;
}
}
}
2.3、边框
因为要求边框与被装饰物一致性,因此边框也要继承Display类
2.3.1、边框统一父类
public abstract class Border extends Display {
protected Display display;
public Border(Display display) {
this.display = display;
}
}
2.3.2、边框1-两边边框
public class SideBorder extends Border{
private char borderChar;
public SideBorder(Display display, char borderChar) {
super(display);
this.borderChar = borderChar;
}
@Override
public int getColumns() {
return 2+display.getColumns();
}
@Override
public int getRows() {
return display.getRows();
}
@Override
public String getRowText(int row) {
return borderChar+display.getRowText(row)+borderChar;
}
}
2.3.3、边框2-包围边框
public class FullBorder extends Border{
public FullBorder(Display display) {
super(display);
}
@Override
public int getColumns() {
return 2+display.getColumns();
}
@Override
public int getRows() {
return 2+display.getRows();
}
@Override
public String getRowText(int row) {
if (row == 0 || row == display.getRows() + 1) {
return "+"+makeLine('-', display.getColumns())+"+";
}
return "|"+display.getRowText(row-1)+"|";
}
private String makeLine(char c,int count) {
StringBuffer s=new StringBuffer();
for (int i = 0; i < count; i++) {
s.append(c);
}
return s.toString();
}
}
2.4、测试
public class Main {
public static void main(String[] args) {
StringDisplay hello_world = new StringDisplay("Hello World");
SideBorder b1 = new SideBorder(hello_world, '#');
FullBorder b2 = new FullBorder(b1);
hello_world.show();
b1.show();
b2.show();
}
}
运行结果:
还可以不断进行“套娃”,形成更复杂的结构
3、tips
- 在先前已经强调过,Border也要作为Display的子类,这样能够和被装饰物一样的,暴露相同的接口,就算被装饰物被隐蔽在边框中,接口也能向外暴露被装饰物的信息,实现了透明性。得益于这种透明性,边框也可以被视为被装饰物。
- 装饰器运用范围很广,如Spring框架中我们熟悉的AOP,不就是一种框架提供的装饰器;而在python语言中,甚至直接为使用者提供了语言层面的@property装饰器