Android 設計模式 - 裝飾者模式
1. 定義
使用裝飾者模式可以在執行時動態地擴充一個類的功能,它提供了比繼承更具彈性的代替方案。
在裝飾模式中的角色有:
- 抽象構件(Component)角色: 給出一個抽象介面,以規範準備接收附加責任的物件。
- 具體構件(ConcreteComponent)角色: 定義一個將要接收附加責任的類。
- 裝飾(Decorator)角色: 持有一個構件(Component)物件的例項,並定義一個與抽象構件介面一致的介面。
- 具體裝飾(ConcreteDecorator)角色: 負責給構件物件「貼上」附加的責任。
2. 實現
下面就以買豆漿為例,實現一個裝飾者模式。在買豆漿時,我們可以選擇原味的,然後再新增紅豆、綠豆等原料,從而磨出多種口味的豆漿。那麼,這個新增的原料就屬於對原味豆漿的擴充套件,所以使用裝飾者模式再好不過了。

類圖
- 定義抽象構件角色,即豆漿和原料共同的介面。
public interface IMilk { /** * 描述 * * @return */ String getDescription(); /** * 價格 * * @return */ double cost(); }
- 定義具體構件角色,即被裝飾的原味豆漿。
public class SoybeanMilk implements IMilk { @Override public String getDescription() { return "原味"; } @Override public double cost() { return 2; } }
- 定義裝飾角色,用來加入豆漿的原料。
public abstract class MilkAddition implements IMilk { protected IMilk milk; public MilkAddition(IMilk milk){ this.milk = milk; } }
- 定義具體裝飾角色,即加入的不同原料。
public class RedBeanAddition extends MilkAddition { public RedBeanAddition(IMilk milk) { super(milk); } @Override public String getDescription() { return milk.getDescription() + " + 紅豆"; } @Override public double cost() { return milk.cost() + 3; } } public class MungBeanAddition extends MilkAddition { public MungBeanAddition(IMilk milk) { super(milk); } @Override public String getDescription() { return milk.getDescription() + " + 綠豆"; } @Override public double cost() { return milk.cost() + 2; } } public class SugarAddition extends MilkAddition { public SugarAddition(IMilk milk) { super(milk); } @Override public String getDescription() { return milk.getDescription() + " + 糖"; } @Override public double cost() { return milk.cost() + 0.5; } }
測試:
// 原味豆漿,兩塊錢 IMilk milk = new SoybeanMilk(); // 加糖,五毛錢 milk = new SugarAddition(milk); // 加紅豆,三塊錢 milk = new RedBeanAddition(milk); // 加綠豆,兩塊錢 milk = new MungBeanAddition(milk); System.out.println("喝到的豆漿:" + milk.getDescription() + ", 價格:" + milk.cost() + "元"); // 輸出:喝到的豆漿:原味 + 糖 + 紅豆 + 綠豆, 價格:7.5元
3. 應用
-
優點:
- 裝飾者模式與繼承關係的目的都是要擴充套件物件的功能,但是裝飾者可以提供比繼承更多的靈活性。
- 通過使用不同的具體裝飾類以及這些裝飾類的排列組合,設計師可以創造出很多不同行為的組合。
- 具體構件類與具體裝飾類可以獨立變化,使用者可以根據需要增加新的具體構件類和具體裝飾類,原有類庫程式碼無須改變,符合「開閉原則」。
-
缺點:
- 這種比繼承更加靈活機動的特性,也同時意味著更加多的複雜性,使用時更容易出錯。
- 裝飾模式會導致設計中出現許多小類,如果過度使用,會使程式變得很複雜。
-
使用場景:
- 在不影響其他物件的情況下,以動態、透明的方式給單個物件新增職責。
- 當不能採用繼承的方式對系統進行擴充套件,或者採用繼承不利於系統擴充套件和維護時,可以使用裝飾模式。
Java IO 模組使用了不少裝飾者模式,比如我們經常會這麼寫:
new DataInputStream(new BufferedInputStream(new FileInputStream("README.md")));
起初學習 IO 部分的時候就是一頭霧水,心想怎麼會包裝這麼多層,誰記得住這麼多程式碼。現在來看,不過是裝飾者模式的應用罷了,這就是進步吧。 _
【附錄】

資料圖