Java結構型設計模式 —— 用裝飾者模式來賣煎餅果子

一、引言

9月30號上映,《我和我的祖國》這個電影,小編不知道你們看了沒,還挺不錯的。

其中講述了新中國成立、中國女排、香港迴歸、首顆原子彈爆炸等等歷史性的事件,小編再一次體會到中國的強大。

國慶節假期現在是第四天了,去年這個時候小編還記得再寫redis相關操作,年復一年。

二、裝飾者定義

結構型設計模式,動態的將新功能附加到對象上,在對象功能擴展方面,他比繼承更加有彈性,裝飾者模式也體現了開閉原則。

那裝飾者有什麼優點呢? 可能剛一開始說還看不太明白,看完具體案例分析實現,再回頭來看,是否理解。

1、擴展一個類的功能,或者給一個類增加附加職責。

2、通過這些不同的裝飾者,可以使被裝飾者實現不同的效果。

3、符合開閉原則,可以在不改變原有類的情況下,給個對象添加新的功能。

三、裝飾者案例分析

你們喜歡喫手抓餅嘛? 

小編喫手抓餅喜歡加培根肉鬆,再外加一瓶牛奶,完美解決早餐。

那就以這個生活爲案例,假設現在有一款手抓餅的產品,可以加多份不同的配料,然後計算最後的價格。

小夥伴們可以先想想,如果要你現在設計這麼一個功能,你會怎麼去設計?

注意:一個手抓餅可以加兩份培根,一份肉鬆等等,還需要注意程序的可擴展性、維護性。

裝飾者就比較適合這種場景來使用,下面進行角色分析

1、抽象產品:被裝飾者基類,用來定義被裝飾者的行爲和方法

2、被裝飾者:具體的裝飾者類,可以動態添加新的功能(比如一個手抓餅可以加雞蛋、火腿等等)。

3、抽象裝飾者:需要聚合或者組合具體被裝飾者,還需要繼承或者實現抽象產品

4、裝飾者:持有被裝飾者對象,並且進行新功能的添加

四、裝飾者案例實現

步驟一:首先我們需要創建產品,產品是主要內容,裝飾是其次(首先你要有煎餅果子可以賣,纔可以加火腿之類的)。

/**
 * @Auther: IT賤男
 * @Date: 2019/8/21 13:54
 * @Description: 產品抽象類
 */
public interface Apancake {

    /**
     * 產品描述
     * @return
     */
    String getDesc();

    /**
     * 產品價格
     * @return
     */
    int cost();

}

/**
 * @Auther: IT賤男
 * @Date: 2019/8/21 13:56
 * @Description: 被裝飾者 - 煎餅果子
 */
public class BatterCake implements Apancake {

    @Override
    public String getDesc() {
        return "煎餅果子";
    }

    @Override
    public int cost() {
        return 5;
    }
}

步驟二:現在具體產品有了,那麼光一個煎餅果子也不夠喫呀,商家還提供了可以加火腿、雞蛋這個配料。

/**
 * @Auther: IT賤男
 * @Date: 2019/8/21 13:57
 * @Description: 抽象裝飾者 - 實現產品接口
 */
public class AbstractDecorate implements Apancake {

    // 聚合一個具體的被裝飾者
    protected Apancake apancake;

    public AbstractDecorate(Apancake apancake) {
        this.apancake = apancake;
    }

    @Override
    public String getDesc() {
        // 調用被裝飾者的方法
        return this.apancake.getDesc();
    }

    @Override
    public int cost() {
        // 調用被裝飾者的方法
        return this.apancake.cost();
    }
}
/**
 * @Auther: IT賤男
 * @Date: 2019/8/21 14:02
 * @Description: 火腿腸裝飾者 -> 繼承抽象抽象裝飾者
 */
public class SausageDecorate extends AbstractDecorate {

    public SausageDecorate(Apancake apancake) {
        super(apancake);
    }

    @Override
    public String getDesc() {
        // 首先需要調用父類的方法,獲取原本結果的基礎之上,新增新功能
        return super.getDesc() + "加一個火腿腸加兩元";
    }

    @Override
    public int cost() {
        // 首先需要調用父類的方法,獲取原本的價格,加一根火腿的價格
        return super.cost() + 2;
    }
}
/**
 * @Auther: IT賤男
 * @Date: 2019/8/21 13:59
 * @Description: 雞蛋裝飾者 -> 繼承抽象抽象裝飾者
 */
public class EggDecorate extends AbstractDecorate {

    public EggDecorate(Apancake apancake) {
        super(apancake);
    }

    @Override
    public String getDesc() {
        return super.getDesc() + "加一個雞蛋一元";
    }

    @Override
    public int cost() {
        return super.cost() + 1;
    }
}

步驟三:測試,現在來了一個客人,需要一個加雞蛋、火腿的煎餅果子。 原本只是一個普通的煎餅果子,經過裝飾者這麼一操作之後,就變得不普通了。

/**
 * @Auther: IT賤男
 * @Date: 2019/8/21 14:03
 * @Description:
 */
public class Test {

    public static void main(String[] args) {
        // 商家先做一個煎餅果子出來
        Apancake batterCake = new BatterCake();
        System.out.println(batterCake.getDesc() + " 價格:" + batterCake.cost());
        System.out.println("-------------------------");

        // 把做出來的煎餅果子加雞蛋
        batterCake = new EggDecorate(batterCake);
        System.out.println(batterCake.getDesc() + " 價格:" + batterCake.cost());

        // 把已經加好雞蛋的煎餅果子,再加一個火腿
        System.out.println("-------------------------");
        batterCake = new SausageDecorate(batterCake);
        System.out.println(batterCake.getDesc() + " 價格:" + batterCake.cost());

    }

}
煎餅果子 價格:5
-------------------------
煎餅果子加一個雞蛋一元 價格:6
-------------------------
煎餅果子加一個雞蛋一元加一個火腿腸加兩元 價格:8

三、裝飾者模式和橋接模式區別

橋接模式的定義是將抽象與實現分離(用組合聚合的方式,而不是使用繼承),使得兩者可以獨立變化,可以減少創建新的類。這樣看起來和裝飾者模式差不多,但是兩者還是有一些區別。

1、橋接模式中所指的分離,是將抽象和實現分離,而裝飾者只是基於屬性的行爲進行封裝成獨立的類。

2、橋接模式中的行爲之間是沒有關聯的,而裝飾者模式中的行爲具有可疊加性,其表現出來的結果是一個整體。

3、兩者都可以減少子類過多的問題。

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