設計模式之裝飾者模式

  裝飾者(Decorator)模式就是在不修改任何底層代碼的狀況下,給對象賦予新的職責編程

  裝飾者模式又稱包裝模式,即:在真實對象的外層包裝一層層新的職能。設計模式

  裝飾者模式主要採用組合的方式拓展對象的行爲,是給愛用繼承的人一個全新的設計眼界。(繼承是在編譯時靜態決定對象的行爲,而組合是在運行時動態地擴展對象的行爲。)架構

  須要格外注意的是:裝飾者與被裝飾者必須是同一個類型,即:具備相同的超類。【這裏經過繼承實現類型匹配】ide

  裝飾者模式包含四個角色:抽象目標組件,具體目標組件,抽象裝飾者,具體裝飾者。其中,目標組件就是須要被裝飾的對象。優化

 

1.抽象目標組件(Component)this

  目標組件的抽象類,是全部裝飾者與具體組件的超類。這是爲了保持組件被裝飾後,返回的對象類型保持不變spa

public abstract class Beverage {

    protected String description = "Unknown Beverage";

    public String getDescription() {
        return description;
    }

    public abstract BigDecimal cost();
}

 

2.具體目標組件設計

  須要賦予新權限的組件。3d

public class DarkRoast extends Beverage{

    public DarkRoast() {
        description = "Dark Roast";
    }
    
    @Override
    public BigDecimal cost() {
//定義深焙飲料的價格
return new BigDecimal(0.25); } }

 

3.抽象裝飾者code

//須要在飲料中添加的調味品
//具備兩個抽象方法:getDescription()、cost()
public
abstract class Condiment extends Beverage { public abstract String getDescription(); }

 

4.具體裝飾者

public class Mocha extends Condiment{

    private Beverage beverage;
    
    public Mocha(Beverage beverage) {
        super();
        this.beverage = beverage;
    }

    @Override
    public String getDescription() {
     //在原有飲料的描述中增添添加劑的描述
return beverage.getDescription() + ", Mocha"; } @Override public BigDecimal cost() {
//返回飲料加上添加劑的總價。0.6是摩卡添加劑的價格
return new BigDecimal(0.6).add(beverage.cost()).setScale(2, BigDecimal.ROUND_HALF_UP); } }
public class Whip extends Condiment{

    private Beverage beverage;
    
    public Whip(Beverage beverage) {
        super();
        this.beverage = beverage;
    }

    @Override
    public String getDescription() {
        return  beverage.getDescription() + ", Whip";
    }

    @Override
    public BigDecimal cost() {
        return new BigDecimal(0.5).add(beverage.cost()).setScale(2, BigDecimal.ROUND_HALF_UP);
    }

}

 

5.Demo

public class BeverageDemo {

    public static void main(String[] args) {
        Beverage beverage = new DarkRoast();
        System.out.println(beverage.getDescription() +" : " + beverage.cost());
        
        
        //use mocha & whip to decorate dark-roast.
        beverage = new Mocha(beverage);
        beverage = new Whip(beverage);
        System.out.println(beverage.getDescription() +" : " + beverage.cost());
        /*Log:
         * Dark Roast : 0.25
         * Dark Roast, Mocha, Whip : 1.35*/
    }
}

 

6.備註

  裝飾模式是 針對抽象組件(Component)類型編程。可是,若是你要針對具體組件編程時,就應該從新思考你的應用架構,以及裝飾者是否合適。固然也能夠改變Component接口,增長新的公開的行爲,實現「半透明」的裝飾者模式。在實際項目中要作出最佳選擇。
 
     裝飾模式會致使設計中出現許多小類,若是過分使用,會使程序變得很複雜。【能夠經過工廠模式和生成器模式進行優化】
 
7.拓展
    7.1  若是隻有一個Concrete Component類而沒有抽象的Component接口時,可讓Decorator繼承Concrete Component。
    7.2  若是隻有一個Concrete Decorator類時,能夠將Decorator和Concrete Decorator合併。
 
8.使用場景
    8.1 須要 擴展一個類的功能,或給一個類添加附加職責。
    8.2 須要動態的 給一個對象添加功能,這些功能能夠再動態的撤銷。
    8.3 須要 增長由一些基本功能的排列組合而產生的很是大量的功能,從而使繼承關係變的不現實。
    8.4 當不能採用生成子類的方法進行擴充時。一種狀況是,可能 有大量獨立的擴展,爲支持每一種組合將產生大量的子類,使得子類數目呈爆炸性增加。另外一種狀況多是由於 類定義被隱藏,或類定義不能用於生成子類
 

9. 補充

  Java I/O是裝飾者模式的典型例子。

 

10. 參考資料

    10.1 O'Reilly:《Head First設計模式》

    10.2 百度百科 : 《裝飾者模式》

相關文章
相關標籤/搜索