設(shè)計模式系列篇(七)——裝飾器模式

What

裝飾器模式(Decorator Design Pattern),是面向?qū)ο缶幊填I(lǐng)域中,一種動態(tài)地往一個類中添加新的行為的設(shè)計模式。就功能而言,裝飾模式相比生成子類更為靈活,這樣可以給某個對象而不是整個類添加一些功能。裝飾器模式背后設(shè)計思想是“組合大于繼承”。它主要的作用是給原始類添加增強功能。這也是判斷是否該用裝飾器模式的一個重要的依據(jù)。

Why

  1. 一般的,我們?yōu)榱藬U展一個類經(jīng)常使用繼承方式實現(xiàn),由于繼承為類引入靜態(tài)特征,并且隨著擴展功能的增多,子類會很膨脹。因此,如果在不想增加很多子類的情況下擴展類,我們就可以使用裝飾器模式來實現(xiàn)。
  2. 裝飾類和被裝飾類可以獨立發(fā)展,不會相互耦合,裝飾模式是繼承的一個替代模式,裝飾模式可以動態(tài)擴展一個實現(xiàn)類的功能。

How

現(xiàn)在的年輕人大多喜歡喝奶茶,奶茶有很多口味,而且每種口味又可以添加很多配料,比如布丁、紅豆、珍珠等等,會有非常非常多的搭配方式,很難去枚舉所有搭配組合。今天就以去買奶茶的例子來給大家講解裝飾器模式的典型實現(xiàn)。

// 首先,創(chuàng)建奶茶接口:
public interface MilkTea {
    void make();

    Integer price();
}

// 原味奶茶,價格10元
public class OriginMilkTea implements MilkTea{
    @Override
    public void make() {
        System.out.println("This is an origin milk tea.");
    }

    @Override
    public Integer price() {
        return 10;
    }
}

// 這個類主要目的是方便后面的子類在實現(xiàn)的時候可以只關(guān)注要增強的方法即可。
public class FilterMilkTea implements MilkTea {
    protected MilkTea milkTea;

    public FilterMilkTea(MilkTea milkTea) {
        this.milkTea = milkTea;
    }

    @Override
    public void make() {
        this.milkTea.make();
    }

    @Override
    public Integer price() {
        return this.milkTea.price();
    }
}

// 另加珍珠,2元
public class MilkTeaWithPearl extends FilterMilkTea {

    public MilkTeaWithPearl(MilkTea milkTea) {
        super(milkTea);
    }

    @Override
    public void make() {
        this.milkTea.make();
        System.out.println("Add pearl");
    }

    @Override
    public Integer price() {
        return this.milkTea.price() + 2;
    }
}

// 另加布丁,3元
public class MilkTeaWithPudding extends FilterMilkTea {

    public MilkTeaWithPudding(MilkTea milkTea) {
        super(milkTea);
    }

    @Override
    public void make() {
        this.milkTea.make();
        System.out.println("Add pudding");
    }

    @Override
    public Integer price() {
        return this.milkTea.price() + 3;
    }

}

// 另外加糖,免費,正是因為有了FilterMilkTea,price方法可以不用重寫
public class MilkTeaWithSugar extends FilterMilkTea {

    public MilkTeaWithSugar(MilkTea milkTea) {
        super(milkTea);
    }

    @Override
    public void make() {
        this.milkTea.make();
        System.out.println("Add sugar");
    }
}

測試效果如下:

// 我:我要來一杯奶茶,加布丁、珍珠和糖。
// 店員:你好,總共15元。
public class TestMain {
    public static void main(String[] args) {
        MilkTea milkTea = new OriginMilkTea();
        MilkTeaWithPearl milkTeaWithPearl = new MilkTeaWithPearl(milkTea);
        MilkTeaWithPudding milkTeaWithPudding = new MilkTeaWithPudding(milkTeaWithPearl);
        MilkTeaWithSugar milkTeaWithSugar = new MilkTeaWithSugar(milkTeaWithPudding);
        milkTeaWithSugar.make();
        System.out.println(String.format("It costs you %d RMB", milkTeaWithSugar.price()));
    }
}

輸出結(jié)果為:

This is an origin milk tea.
Add pearl
Add pudding
Add sugar
It costs you 15 RMB

裝飾器的實現(xiàn)方法其實和代理模式很像,不過兩者解決問題的側(cè)重點是完全不同的。代理模式主要增加的是非功能性需求,而裝飾器模式則是增加的功能性需求。

代碼地址

i-learning

寫在最后

如果你覺得我寫的文章幫到了你,歡迎點贊、評論、分享、贊賞哦,你們的鼓勵是我不斷創(chuàng)作的動力~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容