装饰器模式(装饰边框与被装饰物的一致)
用处
为对象添加装饰,使其增加新的功能
角色
- Component
增加功能时的核心角色。只定义了方法(API) - ConcreteComponent
该角色是实现了Component角色所定义方法(API)的具体角色 - Decorator(装饰物)
该角色是具有与Component角色相同的方法(API),它内部保存了被装饰对象——Component角色。Decorator就角色知道自己要装饰的对象 - ConcreteDecorator(具体的装饰物)
该角色是具体的Decorator角色。
类图
由类图可知
- 被装饰物ConcreteComponent和装饰器Decorator都是Component类的子类,Decorator类中聚合了Component接口,因此装饰器对象中可以聚合装饰器对象Decorator,也可以聚合被装饰物ConcreteComponent,就像Decorator就像画框一样,ConcreteComponent像画一样,可以在画的外面套无限层画框(装饰器),每个装饰器可以实现不同的功能增强。
举例
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角色
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));
}
}
}
//ConcreteComponent角色
class StringDisplay extends Display{
private String string;
public StringDisplay(String string){
this.string = string;
}
public int getColumns(){
return string.getBytes().length;
}
public int getRows(){
return 1;
}
public String getRowText(int row){
if(row == 0 ){
return string;
}else{
return null;
}
}
}
//Decorator角色
abstract class Border extends Display{
protected Display display;
protected Border(Display display){
this.display = display;
}
}
//ConcreteDecorator角色
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;
}
}
//ConcreteDecorator角色
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) + "|";
}
}
private String makeLine(char ch,int count){
StringBuffer buf = new StringBuffer();
for(int i = 0 ;i<count;i++){
buf.append(ch);
}
return buf.toString();
}
总结
- 符合开闭原则
- 在装饰器模式中,装饰器与被装饰物具有一致性(具有相同的方法API),因此即使被装饰物 被 装饰器 装饰起来了,API也不会隐藏,依然可以调用方法。
- 使用委托,使类之间弱关联