裝飾者模式

在談裝飾這模式之前,我想讓大家思考一下,我們開發的時候爲什麼要遵守開閉原則(對拓展開放,對修改關閉)?這看起來是一個非常矛盾的事情,又要拓展功能,又不能夠修改已有的代碼。其實,這樣做最主要的原因是防止因爲修改已有代碼引入新的BUG,已有的代碼一般都是經過檢測的,很少有BUG,如果直接在上面修改的話,很可能導致未知的錯誤,可能引起別的組件的故障,甚至癱瘓整個系統。

在明白上述這一點之後,我們就比較容易理解那些明明兩三行代碼就能完成的功能,爲什麼要在上面做各種抽象了,主要是爲了三個方面:

  1. 代碼重用(從更長遠的角度看起來,簡化開發)
  2. 易於拓展(增加功能方便)
  3. 便於維護(不修改已有代碼,結構層次清晰)

OK,下面進入正題

我們假設以下情景:有一家DIY奶茶廠商,要管理很多飲品,不同的配方就是一種產品,假設主料有茶,咖啡等等,配料有紅豆,糖,牛奶,等等,我們要科學的對這些材料進行管理,按照面向對象的思維,每一種產品就是一個類,我的天,無數的組合豈不是無窮無盡的類,這樣設計顯然是不科學的。我們這時候可以用裝飾者模式,我們看看裝飾者模式是如何做的

我們先來觀察這些產品有何特點:都是由主料和多種輔料複合而成的,這時候我們就要想辦法,如何動態的去給主料裏添加輔料,而不是在編譯的時候直接寫死

先上類圖

這裏寫圖片描述
我們把主料和輔料裝飾者都實現Beverage接口,這樣做的作用最後再說。下面我們來看看代碼

public interface Beverage {
    String discription();
    float cost();
}

奶茶的代碼和咖啡一樣,我就不重複了

public class Coffee implements Beverage{
    public String discription() {
        return "咖啡";
    }

    public float cost() {
        return 5;
    }
}
//抽象方法,啥也沒做
public abstract class IngredientsDecorator implements Beverage{

}

下面幾個輔料的方法也幾乎一致,我就只寫一個了

public class Pudding extends IngredientsDecorator{
    //被裝飾對象
    Beverage beverage;
    //要裝飾哪個對象就傳哪個
    public Pudding(Beverage beverage){
        this.beverage=beverage;
    }
    //增強描述功能
    public String discription() {
        return beverage.discription()+",布丁";
    }
    //增強付款功能
    public float cost() {
        return beverage.cost()+2;
    }
}

我們寫個測試代碼

public static void main(String[] args) {
        Coffee coffee=new Coffee();
        Ice coffeeIce=new Ice(coffee);
        Sugar cISugar=new Sugar(coffeeIce);
        System.out.println(cISugar.cost());
        System.out.println(cISugar.discription());
    }
    輸出:
    6.0
    咖啡,冰,糖

我們來看看之前留下的問題,爲什麼要裝飾者要實現Beverage類?

 public Pudding(Beverage beverage){
        this.beverage=beverage;
    }

看看這個代碼,其實就是爲了這段代碼,裝飾對象可以不斷的被裝飾,也就實現了加各種輔料

這裏說一下繼承,繼承不僅僅是爲了代碼重用,還有一個作用就是保持類型的一致,我們裝飾者模式主要就是利用了後面這一點

我們可以看到,用這種DIY組合的方式就能達到我們的需求,就不用寫那麼多的類了

但是裝飾者模式也有不少的缺點:

  1. 可能裝飾類會非常多
  2. 如果被裝飾對象經過多次裝飾,可能會導致結構非常複雜
  3. 如果需要的對象需要進過多次裝飾,那麼人爲的去組裝是非常難以保證正確性的

其實對於複雜的裝飾,我們一般會採用工廠模式去進行裝飾,這樣就不必去關注這些實現細節了

裝飾者模式是一種非常常見的模式,他能在不修改源代碼的情況下,動態的給原對象賦予新的功能,最常見的IO類就大量使用了裝飾者模式

PS:源碼地址

發佈了41 篇原創文章 · 獲贊 32 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章