概念
裝飾模式能夠在不改變原類文件和繼承的情況下,動態的寬展一個對象的功能,通過創建一個包裝對象來包裹真實的對象。
模式結構
在這幾類角色結構中,必須擴展Component的功能,但Component並不知道Docorator的存在,ConcreteDocorator纔是具體的裝飾對象,起了給Component添加職責的作用。
- 抽象構建角色(Component):抽象接口,用來規範準備接口附加責任的對象;
- 具體構建角色(ConcreteComponent):定義一個將要接口附加責任的類;
- 裝飾角色(Docorator):定義一個與抽象構建角色一致的接口,持有一個抽象構建角色的引用;
- 具體的裝飾角色(ConcreteDocorator):負責給構建角色添加附加責任。
示例說明
/** * 抽象構建角色 */ public interface Icomponent { void showCoffee(); double showPrice(); } /** * 具體的構建角色 */ class Coffee implements Icomponent{ private String name; private double price; public Coffee(String name, double price) { this.name = name; this.price = price; } @Override public void showCoffee() { System.out.println(this.name+"咖啡"); } @Override public double showPrice() { return this.price; } // 省略get,set方法 } /** * 裝飾角色 */ abstract class Docorator implements Icomponent{ private Icomponent component; public void setComponent(Icomponent component) { this.component = component; } @Override public void showCoffee() { component.showCoffee(); } @Override public double showPrice() { return component.showPrice(); } } /** * 具體的裝飾角色1 */ class Milk extends Docorator{ @Override public void showCoffee() { System.out.print("加奶的"); super.showCoffee(); } @Override public double showPrice() { return 20.0 + super.showPrice(); } } /** * 具體的裝飾角色2 */ class Sugar extends Docorator{ @Override public void showCoffee() { System.out.print("加糖的"); super.showCoffee(); } @Override public double showPrice() { return 10.0 + super.showPrice(); } } class DocoratorClient{ public static void main(String[] args){ Icomponent coffee = new Coffee("藍山", 80.0); Docorator milk = new Milk(); Docorator sugar = new Sugar(); coffee.showCoffee(); System.out.println(coffee.showPrice()); System.out.println("======================================"); milk.setComponent(coffee); milk.showCoffee(); System.out.println(milk.showPrice()); System.out.println("======================================"); sugar.setComponent(milk); sugar.showCoffee(); System.out.println(sugar.showPrice()); } }運行結果:
藍山咖啡
80.0
======================================
加奶的藍山咖啡
100.0
======================================
加糖的加奶的藍山咖啡
110.0
裝飾模式的思考起點就是利用“多用組合,少用繼承”的原則;Java中裝飾模式典型的使用是I/0流;裝飾模式和AOP在思想上有共同之處。
裝飾模式優缺點
- 比繼承更靈活:繼承是靜態的,一旦繼承,多有子類都有同樣的功能;而裝飾則是把功能分散到每個裝飾器中,然後通過對象組合的方式,動態的組合調用;
- 更容易複用功能:功能分散到每個裝飾器中,每個裝飾器的功能相對簡單,有利於複用;
- 簡化高層定義:通過組合個方式給對象增加更多的功能,不需要在定義頂層類的時候把所有的功能都定義出來;
- 會產生很多細粒度對象:由於功能細分到每個裝飾器,這樣裝飾器類會越來越多。