装饰器模式
引入
假设有一块🎂,如果涂上奶油,就是奶油蛋糕。如果加上🍓,就是草莓奶油蛋糕。如果加上🍫,蜡烛,就变成了一块生日蛋糕。
不论时蛋糕,奶油蛋糕,草莓奶油蛋糕还是生日蛋糕,他们的核心都是蛋糕。
首先有一个相当于蛋糕的对象,然后不断的装饰当高一样的不断对其增加功能,他就变成了使用更加明确的对象。
像这样不断的为dui'xdui像添加功能的设计模式称为Decorator模式。 Decorator指的是“装饰物”。
事例程序
类的一览表
名字 | 说明 |
Display | 用于显示字符串的抽象类 |
StringDisplay | 用于显示单行字符的类 |
Border | 用于显示装饰边框的抽象类 |
SideBorder | 用于只显示右边框的类 |
FullBorder | 用于显示上下左右边框的类 |
Main | 测试 |
类图
相关类
Display类
- 抽象类,显示多行字符串
- getColumns(),抽象方法,获取横向字符数
- getRows();抽象方法,获取纵向行数
- getRowText(int row);抽象方法,获取第row行的字符串
- show() 是显示所有行的字符串的方法,调用getRows()获取行数,调用getRowText(int row)获取需要显示的字符串。show方法使用了getRows和getRowText等抽象方法,这属于模板模式。
public abstract class Display { public abstract int getColumns();//获取横向字符数 public abstract int getRows();//获取纵向行数 public abstract String getRowText(int row); //获取第row行的字符串 public final void show() { //全部展示 for (int i = 0; i < getRows(); i++) { System.out.println(getRowText(i)); } } }
StringDisplay类
- 用于显示单行字符串的类。是Display类的子类,实现display的抽象方法。
- string保存要显示的字符串。StringDisplay只显示一行字符串,所以getColumns返回string.getBytes().length,getRows返回固定值1。
- 当获取第0行的时候getRowText才返回string字段。
- 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类
- 装饰边框的抽象类,Display的子类
- 通过继承,装饰边框与被装饰物有了相同的方法,具有了一致性
- Display类型的display字段,表示被装饰物。不过display并不仅限于StringDisplay的实例,因为Border也是Display的子类,display可能是其他装饰边框。
public abstract class Border extends Display { protected Display display;//表示被装饰物 public Border(Display display) { //在生成实例时通过参数指定被装饰物 this.display = display; } }
SideBorder类
- 在字符串两侧装饰边框
效果:
|被装饰物|
public class SideBorder extends Border { private char borderChar; public SideBorder(Display display, char borderChar) { super(display); this.borderChar = borderChar; } @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) { StringBuffer buf = new StringBuffer(); for (int i = 0; i < count; i++) { buf.append(ch); } return buf.toString(); } }
Main
- b1,显示hello world
- b2,b1的两侧加上‘#’
- b3,b2上下左右加上装饰边框
- b4,给hello world加上多重边框
复制代码
public class Main { public static void main(String[] args) { Display b1 = new StringDisplay("hello world"); b1.show(); Display b2 = new SideBorder(b1, '#'); b2.show(); Display b3 = new FullBorder(b1); b3.show(); Display b4 = new SideBorder( new FullBorder( new FullBorder( new SideBorder( new FullBorder( new StringDisplay("hello world") ), '*' ) ) ) , '/'); b4.show(); } }
效果:
hello world #hello world# +-----------+ |hello world| +-----------+ /+-----------------+/ /|+---------------+|/ /||*+-----------+*||/ /||*|hello world|*||/ /||*+-----------+*||/ /|+---------------+|/ /+-----------------+/
登场角色
- Component
增加功能的核心角色,定义蛋糕的接口。——Display - ConcreteComponent
具体的蛋糕。——StringDisplay - Decorator
与Component具有相同的接口,在内部保存了被装饰的对象。——Border - ConcreteDecorator
具体的装饰角色。——SideBorder和FullBorder