2.裝飾者模式----Head First(設計模式進階)

目標

軟件設計目標:正確性、健壯性、靈活性、可重用性、高效性–之後的所有的設計模式,我將會以此來作爲學習的落腳點,其實,設計模式就是代碼結構的設計技巧,有目標才能知道每種模式出現的根本的原因,和解決掉了什麼樣的問題.
就以裝飾者模式作爲開端,打個樣出來,之後會不斷的完善.

場景

星巴茲咖啡連鎖店 ,點咖啡,有多種咖啡,每種咖啡都有標價,名字,
也可以點咖啡加多種調料,調料也有標價和名字,最後的成品的名字是咖啡與調料的組合,價錢是兩種的和.我們做出的功能是每種咖啡都可以加不同且多種的調料(靈 活性),可以得到最後的總價和名字,(隱含的要求:可以隨時添加新品的咖啡,和調料而不用修改原有的代碼(可擴展性))

分析(以下內容如果不好理解可以在看過代碼後再看)

咖啡有標價和名字,調料也有標價和名字,可以抽象出基類component,因爲點咖啡時可以加多種任意調料,而我們需要得到最終的標價和名字,那麼我們怎麼才能做到每添加一種調料都可以獲得最終的標價和名字呢?如果我們的調料類可以獲得上一次添加調料之後的標價和名字的信息,那麼我就可以組合添加新的調料的信息,從而得到最終的信息.那麼顯而易見,調料類的設計應該是包含了component作爲屬性的,爲什麼不是包含了調料作爲屬性呢?因爲第一次是將咖啡類組合進來,其他的時候其實是得到的調料類,這也是爲什麼能用裝飾者模式來解決這個問題的關鍵,咖啡類與調料類有共同的基類(也就是裝飾者與被裝飾者有共同的基類),並且,該基類的屬性和方法正是 該模式傳遞,修飾數據的通道.

注: 數據傳遞也就是 數據來源,數據傳遞通道,數據輸出 是軟件設計或者是代碼設計的基本的組成部分,所有的項目都是這三部分組成,否則,就不是完整的設計.

設計模式正式數據傳遞通道設計的技巧性總結,或者說是抽象.

下面上代碼:

//基礎組價抽象類
public  abstract class Component {

    private String name;

    private Float price;

    abstract void operate();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Float getPrice() {
        return price;
    }

    public void setPrice(Float price) {
        this.price = price;
    }
}
//基礎組件實現類(被裝飾者)
public class Coffee extends Component {
    @Override
    void operate() {
        setName("coffee");
        setPrice(1f);
    }
}
//裝飾者抽象類
public abstract class Flavoring  extends Component{
    //關鍵技巧 持有基類的實例
    private  Component component;
    @Override
    void operate() {
    //遞歸截止條件 component==null
        if (component!=null){
           //執行Component的方法
            component.operate();
        }
    }

    public Component getComponent() {
        return component;
    }

    public void setComponent(Component component) {
        this.component = component;
    }
}
//裝飾者實現類
public class Tang extends Flavoring {
    @Override
    void operate() {
       //先執行Component的方法,實現了遞歸,
        super.operate();
        setName("加糖"+getComponent().getName());
        setPrice(getComponent().getPrice()+2);
    }
}
//裝飾者實現類
public class Yan extends Flavoring{
    @Override
    void operate() {
        super.operate();
        setName("加鹽"+getComponent().getName());
        setPrice(getComponent().getPrice()+1);
    }
}
//測試demo
public class Main {

    public static void main(String [] args){
        Coffee coffee=new Coffee();
        Tang tang=new Tang();
        Yan yan=new Yan();
        //數據傳遞
        tang.setComponent(coffee);
        yan.setComponent(tang);
        //裝飾
        yan.operate();
        System.out.println(tang.getName()+";"+tang.getPrice());
        System.out.println(yan.getName()+";"+yan.getPrice());
    }

}
//輸出結果
加糖coffee;3.0
加鹽加糖coffee;4.0

從測試demo可以看到上述設計師通過setComponent方法作爲裝飾的準備,其實就是一層層嵌套,然後通過operate方法,逆向一層層遞歸,直到Coffee也就是被裝飾者,從而實現了根據嵌套的順序來裝飾Coffee的目的.

技巧

主要是使用組合,通過組合的特性來實現裝飾準備(setComponent)方法,又因爲組合的原因,使我們可以調用component的operate方法實現遞歸的去裝飾被裝飾者Coffee.

operate方法設計技巧:

1.必須在基類中聲明.

2.在裝飾者的基類(Favoring)中的實現邏輯:必須先判斷是否爲null,這是遞歸截止的標誌,否則會報空指針異常,然後調用component的operate方法,這是實現遞歸的通道,在裝飾者的具體實現類中operate方法必須先調用父類的operate方法,其實就是調用自己持有的component中的operate方法

總結

優點:組合的使用可以更加靈活的添加額外的功能,其實裝飾就是額外功能的抽象,裝飾者模式通過持有基類的組合技巧,再通過方法的遞歸調用,實現了特殊的,無數量限制(擴展性),無順序限制(靈活性),可重複(重用性)裝飾效果,可以說是非常的完美了.

不足:當然,結合其他的模式會更加的好用,我們也可以看到被裝飾者Coffee的operate實現是寫死了的,我們可以通過其他模式更靈活的去實現,還有裝飾者的實現類也是同樣的問題,那麼我們就可以通過其他的模式比如策略模式等

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章