装饰器模式

转载:http://blog.51cto.com/liukang/2046423

属于结构型模式,它是作为现有的类的一个包装,是继承关系的一个替代方案。

Java I/O的设计就是采用了装饰者模式,各种InputStreamOutputStream层层嵌套,感觉就像洋葱,如果给装饰者一个形象化的吉祥物,想必非洋葱莫属。

eg:

//装饰器或者被装饰对象者统一实现接口或抽象类
public abstract class Display {
        public abstract int getColumn();
        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));
                }
        }
}

//被装饰对象
public class StringDisplay extends Display {
    private String string;

    public StringDisplay(String string) {
        this.string = string;
    }

    public int getColumn() {
        return string.getBytes().length;
    }

    public int getRows() {
        return 1;
    }

    public String getRowText(int row) {
        if (row == 0) {
            return string;
        } else {
            return null;
        }
    }
}
//装饰器模式的关键:
//
一个装饰者的抽象类,被所有装饰者继承,实现被装饰对象相同的接口(表明装饰者也可以被装饰),并聚合该接口(表面可以接收其他装饰对象),保留装饰积累,层层增强。 //可以有,也可以没有 public abstract class BoardStringDisplay extends Display { protected Display display; protected BoardStringDisplay(Display display) { this.display = display; } }
//某一个装饰者,装饰者装饰别人的时候,也被别人装饰
public class SideBoardStringDisplay extends BoardStringDisplay {

    protected SideBoardStringDisplay(Display display) {
        super(display);
    }

    public int getColumns() {
    //使用父类display成员对象 代理的体现:
return 1 + display.getColumns() + 1; // 文字两侧各增加一个字符 } public int getRows() { return display.getRows(); // 行数不变 } public String getRowText(int row) { return "|" + display.getRowText(row) + "|"; } }
//某一个装饰者
public class FullBoardStringDisplay extends BoardStringDisplay {

    protected FullBoardStringDisplay(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 || 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();
    }
}

最终测试:样凑效果:

public class Client {
    public static void main(String[] args) {
        Display d1 = new StringDisplay("Hello, world!");
        Display d2 = new SideBoardStringDisplay(d1);
     //模拟IO流,层层装饰 Display d3
= new FullBoardStringDisplay( new SideBoardStringDisplay( new FullBoardStringDisplay(d2))); System.out.println("显示字符串>>>>>>"); d1.show(); System.out.println(" 增加两侧边框>>>>>>"); d2.show(); System.out.println(" 再增加全边框、两侧边框、全边框>>>>>>"); d3.show(); } }
//
|Hello, world!|
装饰后:
+-------------+
|Hello, world!|
+-------------+
装饰后:
+---------------+
|+-------------+|
||Hello, world!||
|+-------------+|
+---------------+
 

 StringDisplay是被装饰者,SideBoardStringDisplayFullBoardStringDisplay是装饰器,同时也能够被装饰,因为说到底,它们都是继承自Display,所以可以层层嵌套,不断增强。


装饰器模式的特点:

  1. 接口透明,在不改变被装饰者的前提下增加功能。无论是装饰器还是被装饰者,都有共同的抽象,也许是继承同一个抽象类,也许是实现同一个接口;如此一来,装饰前后的对象都是对外提供同样的服务。就像生日蛋糕(抽象父类或接口),无论是装饰了草莓、还是慕斯、还是巧克力,都还是蛋糕(不改变被装饰者是蛋糕的事实),不会变成一块披萨。
  2. 使用了委托(代理)。装饰器将被装饰的对象(可能会是另一个装饰器实例)作为成员,使得类之间称为弱关联关系,这一点和桥接模式(出发地聚合桥接口,目的地实现桥接口,两侧互不影响)的出发点是一致的。此模式与代理模式有些类似,主要区别在于应用场景和目的,装饰器模式应当为所装饰的对象提供增强功能,而代理模式对被代理的对象施加控制,并不提供对对象本身的增强。

原文地址:https://www.cnblogs.com/brxHqs/p/9578035.html