Author:Gorit
Date:2021年10月17日
Refer:《图解设计模式》
12.1 Decorator
相片 与 相册(装饰边框 与 被装饰物 的一致性)
在产品中,装饰即不断的在产品中增加新功能。
不断为对象添加装饰的设计模式为 Decorator
12.2 示例程序
本章我们做一个给字符串添加“边框”的功能
| 名字 | 说明 |
|---|---|
| Display | 用于显示字符串的抽象类 |
| StringDisplay | 用于显示单行字符串的类 |
| Border | 用于显示边框的抽象类 |
| FullBorder | 用于显示上下左右边框的类 |
| Main | 测试程序行为的类 |
一、Display 类
package Decorator;/*** @Author Gorit* @Date 2021/10/17* @desc 用于显示多行字符串的抽象类***/public abstract class Display {public abstract int getColumns(); // 获取横向字符数public abstract int getRows(); // 获取纵向行数 Template Methodpublic abstract String getRowText(int row); // 获取第 row 行字符串 Template Methodpublic final void show () { // 全部显示for (int i = 0; i < getRows(); i++) {System.out.println(getRowText(i));}}}
二、 StringDisplay
package Decorator;/*** @Author Gorit* @Date 2021/10/17* 代表核心的被装饰物**/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() { // 默认只显示 1 行return 1;}public String getRowText(int row) { // 仅当 row 为 0时,返回if (row == 0) {return string;} else {return null;}}}
三、Border
package Decorator;/*** @Author Gorit* @Date 2021/10/17* Border 和 Display 具有相同的属性和方法* display 代表被装饰物,也有可能是其他装饰物的边框**/public abstract class Border extends Display {protected Display display; // 表示被装饰物protected Border(Display display) { // 在生成实例时通过参数指定被装饰物this.display = display;}}
四、SideBorder
package Decorator;import javafx.geometry.Side;/*** @Author Gorit* @Date 2021/10/17* 具体的装饰边框**/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
package Decorator;/*** @Author Gorit* @Date 2021/10/17* 字符串左右加修饰,SliderBorder 类中可以指定边框字符,FullSlider 类中边框字符是固定的**/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) + "|";}}// 生成一个重复 count 次字符 ch 的字符串private String makeLine(char ch, int count) {StringBuffer bf = new StringBuffer();for (int i = 0; i < count; i++) {bf.append(ch);}return bf.toString();}}
六、Main
package Decorator;/*** @Author Gorit* @Date 2021/10/17**/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 d4 =new SideBorder(new FullBorder(new FullBorder(new SideBorder(new FullBorder(new StringDisplay("你好,世界")),'*'))),'/');d4.show();}}
七、效果
Hello , World b1.show() 显示结果
#Hello , World# b2.show() 显示结果
+———————-+ b3.show() 显示结果
|#Hello , World#|
+———————-+
/+——————————-+/ b4.show() 显示结果
/|+—————————-+|/
/||+———————-+||/
/|||你好,世界|||/
/||+———————-+||/
/|+—————————-+|/
/+——————————-+/
12.3 Decorator 模式中登场的角色
一、Component
增加功能时的核心角色,在本次案例中,装饰前的的蛋糕就是 Component 角色。该角色只是定义了蛋糕的接口(API)。Display 担任此角色
二、 ConcreateComponent
实现 Component 所定义的接口(API),示例程序中由 StringDisplay 担任此角色
三、Decorator(装饰物)
该角色与 Component 具有相同的接口(API),它内部保存了被装饰的对象 —— Component 角色。 Decorator 角色知道自己要装饰的对象。Border 扮演此角色
四、ConcreateDecorator(具体的装饰物)
该角色是具体的 Decorator 角色。由 SideBorder 和 FullBorder 担任此角色
