装饰边框与被装饰物的一致性
1.基本介绍
有一个原型程序作为被装饰者,和装饰者实现同一接口,装饰者则可以去修改加强来自用接口相同的方法,这样不断的为对象添加装饰物的设计模式为装饰者设计模式。
2.具体实例
Display类
抽象类或者接口,供装饰者和被装饰者去实现,这样装饰者就可以通过接口去装饰对象。
/**
* @author Jay
* @date 2019/6/24 22:33
* @description 抽象父类, 定义规范
*/
public abstract class Display {
/**
* 获取横向字符
*
* @return
*/
public abstract int getColumns();
/**
* 获取纵向行数
*
* @return
*/
public abstract int getRows();
/**
* 获取第row行的字符串
*
* @param row
* @return
*/
public abstract String getRowText(int row);
/**
* final修饰,子类无法重构写,父类定义展示规范.所以装饰者必须去
* 修改从接口实现的相同方法,即必须遵循父类中的规范,才会真正的装饰起作用.!
*/
public final void show() {
for (int i = 0; i < getRows(); i++) {
System.out.println(getRowText(i));
}
}
}
StringDisplay类
原型类,具体实现父类的核心方法.被装饰者。
/**
* @author Jay
* @date 2019/6/24 22:37
* @description 实现父类抽象方法, 具体实现, 要被装饰的原型类, 与装饰着实现同一接口.
*/
public class StringDisplay extends Display {
/**
* 要显示的字符串
*/
private String string;
/**
* 从外界传入要显示的字符串
*
* @param string
*/
public StringDisplay(String string) {
super();
this.string = string;
}
@Override
public int getColumns() {
// 传入的字符数
return string.getBytes().length;
}
@Override
public int getRows() {
// 单行显示只有一行
return 1;
}
/**
* 当为0时返回,第0行行返回,因为只有一行.
*
* @param row
* @return
*/
@Override
public String getRowText(int row) {
if (row == 0) {
return string;
} else {
return null;
}
}
}
Border类
装饰者类的抽象类,与被装饰者实现同样接口,或者继承相同的抽象类.所以拥有相同的方法,即有着一致性,同时其中还有一个接口类的字段,表示被装饰物,由于自己本身也是实现接口,所以此字段不仅仅接收被装饰者来装饰,也可以接收装饰者来进一步装饰,实现套嵌,和多次装饰。
/**
* @author Jay
* @date 2019/6/24 22:45
* @description 边框类, 用来装饰其他类的必须要与被装饰类又同样的父类或者实现同样的接口,
* 才能去装饰其中共同的方法.
*/
public abstract class Border extends Display {
/**
* 表示被装饰物,接口类型,表示只要实现同一接口即可去装饰
*/
protected Display display;
/**
* 生成实例时通过参数指定被装饰物,也就是说将被装饰者传入装饰者对象去处理.
*
* @param display
*/
public Border(Display display) {
super();
this.display = display;
}
}
SideBroder类
/**
* @author Jay
* @date 2019/6/24 22:52
* @description
*/
public class SideBorder extends Border {
private char borderChar;
public SideBorder(Display display, char ch) {
super(display);
this.borderChar = ch;
}
/**
* 字符数为字符串字符数加上俩测边框字符数
*
* @return
*/
@Override
public int getColumns() {
return 1 + display.getColumns() + 1;
}
@Override
public int getRows() {
return display.getRows();
}
/**
* 对方法加强,加以修饰,加上俩侧边框
*
* @param row
* @return
*/
@Override
public String getRowText(int row) {
return borderChar + display.getRowText(row) + borderChar;
}
}
FullBroder
/**
* @author Jay
* @date 2019/6/24 22:55
* @description 另一个装饰类
*/
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) + "|";
}
}
/**
* 生成重复count次字符串
*
* @param ch
* @param count
* @return
*/
private String makeLine(char ch, int count) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < count; i++) {
sb.append(ch);
}
return sb.toString();
}
}
Main
/**
* @author Jay
* @date 2019/6/24 22:59
* @description
*/
public class Main {
public static void main(String[] args) {
Display d1 = new StringDisplay("Hello World!");
d1.show();
Display d2 = new SideBorder(d1, '#');
d2.show();
Display d3 = new FullBorder(d1);
d3.show();
//由于装设者类也实现了此接口,所以可以将装设者类传入构造函数当作原型进一步装饰.
Display d4 = new SideBorder(new SideBorder(new FullBorder(new StringDisplay("Hello World!")),'&'), '*');
d4.show();
}
}
Hello World!
#Hello World!#
+------------+
|Hello World!|
+------------+
*&+------------+&*
*&|Hello World!|&*
*&+------------+&*
3.登场角色
Compontent
增强功能时的核心角色
ConcreteCompontent
具体实现了接口中的规定方法.原型角色.
Decorator(装饰者)
与Compontent拥有现相同的接口,内部保存了Compontent
ConcreteDecorator(具体装饰者)
具体实现装饰功能.
4.拓展
接口的透明性
装饰者和被装饰者的一致性,即使被装饰者被装饰者装饰起来了,其他类依然可以调用接口的方法,这就是接口的透明性.由于其透明性所以装饰者可以作为新的被装饰者被装饰,形成类似组合模式的递归结构,目的不同,装饰者主要是为了增强对象的功能。
不改变被装饰者增加功能
在修饰时,并不需要改变被装饰者的内部结构即可增加功能.使用了委托的模式,只增加修饰其方法,核心功能委托给被装饰去实现。
模式缺点是导致程序中增加许多功能类似的小类.
java.io中
Reader reader = new FileReader("a.txt");
使用缓冲多次包装。
5.相关设计模式
适配器模式
装饰者模式可以在不改变被装饰者的接口的前提下,增强被装饰者.(透明性)
适配器模式用来适配俩个不同的接口。
策略模式
装饰者是在原型的基础上增强.
策略模式是整体替换.
6.继承和委托
继承中子类可以继承父类方法,因此子类和父类是一致性的,父类引用可以接收子类实例化对象,因为子类可以当作父类看待,反过来就需要类型转换。
委托类和被委托对象实现了同一个接口,同时委托类中包含该接口字段,因此可以委托被委托对象,其中拥有相同的方法,因此也拥有一致性。