裝飾者模式(Decorator Pattern)——給愛用繼承的人一個全新的設計眼界

概述

     裝飾者模式(Decorator Pattern),別名(Warpper)。 動態的將責任附加到對象上。若要擴展功能,裝飾者提供比繼承更有彈性的替代方案。

     裝飾者模式從屬的大類是結構型模式(該大類下的設計模式關注類和對象的組合。繼承的概念被用來組合接口和定義組合對象獲得新功能的方式)。

     涉及的設計原則:

     1. 開放–關閉原則類(應該對擴展開放,對修改關閉)

     2. 多用組合,少用繼承

類圖

這裏寫圖片描述

需要注意的東西

     由上面類圖可知,裝飾者模式,由Component(抽象組件)、ConcreteComponent(具體組件)、Decorator(抽象裝飾類)、ConcreteDecorator(具體裝飾類)組成。其主要功能從上面類圖可以看出。在此需要注意幾點:

  1. 上述中Components和Decorator均可以是接口也可以是抽象類。
  2. 裝飾者和被裝飾者需要實現相同的接口或者抽象類。即裝飾者和被裝飾者對象擁有相同的超類。
  3. 可以用一個或多個裝飾者包裝一個對象。
  4. 裝飾者模式的用意是包喫接口並增加對象的職責。
  5. 一張圖看懂裝飾者模式流程。

這裏寫圖片描述

應用場景

     星巴克咖啡對其出售的咖啡的一種銷售策略的價格做一下統計、這樣當顧客點了他們想要的搭配的時候我們就可以知道最後的價格是多少。

     假設有四種咖啡:HouseBlend、DarkRoaat、Decaf、Espresso。

     同樣有四種配料可以選擇:Milk、Mocha、Soy、Mocha。

     這四種咖啡有不同的價格、同樣四種搭配也有不同的價格。當我們把這個單子拿給顧客的時候、顧客可以任意點一種咖啡、可以任意搭配。我們的目的是要統計每種搭配的價格、那我們要怎麼來實現呢?當我們要添加一個或多個新的品種或者配料的時候,又如何有效的解決這個問題呢?這就是裝飾者模式的解決的問題。

代碼實現

這裏爲了簡化代碼,只採用兩種咖啡HouseBlend、Espresso,兩種配料Mocha、Mocha,這樣的搭配。

package decorator;

/**
 * <p>ClassName      Beverage
 * <p>Description    超類
 * <p>Author         ChongLou
 * <p>Version
 * <p>Date           2017/7/24 0:51
 */
public abstract class Beverage {
    String description = "unknow Beverage";

    public String getDescription() {
        return description;
    }

    /**
     * 計算花費
     *
     * @return
     */
    public abstract Double cost();
}
package decorator;

/**
 * <p>ClassName      CondimentDecorator
 * <p>Description   配料抽象類
 * <p>Author         ChongLou
 * <p>Version
 * <p>Date           2017/7/24 0:55
 */
public abstract class CondimentDecorator extends Beverage {
    /**
     * 所有的配料裝飾者都需要重寫getDescription
     */
    public abstract String getDescription();
}
package decorator;

/**
 * <p>ClassName      Espresso
 * <p>Description    一種飲品(具體的組件)
 * <p>Author         ChongLou
 * <p>Version
 * <p>Date           2017/7/24 1:01
 */
public class Espresso extends Beverage {
    public Espresso() {
        description = "Espresso";
    }

    public Double cost() {
        return 1.99;
    }
}
package decorator;

/**
 * <p>ClassName      HouseBlend
 * <p>Description    另外一種飲品(具體的組件)
 * <p>Author         ChongLou
 * <p>Version
 * <p>Date           2017/7/24 1:04
 */
public class HouseBlend extends Beverage {
    public HouseBlend() {
        description = "HouseBlend";
    }

    public Double cost() {
        return 0.89;
    }
}
package decorator;

/**
 * <p>ClassName      Mocha
 * <p>Description    具體裝飾者
 * <p>Author         ChongLou
 * <p>Version
 * <p>Date           2017/7/24 1:05
 */
public class Mocha extends CondimentDecorator {
    Beverage beverage; //被裝飾者

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

    public String getDescription() {
        return beverage.getDescription() + ",Mocha";
    }

    public Double cost() {
        return 0.2 + beverage.cost();
    }
}
package decorator;

/**
 * <p>ClassName      Whip
 * <p>Description    具體裝飾者
 * <p>Author         ChongLou
 * <p>Version
 * <p>Date           2017/7/24 1:12
 */
public class Whip extends CondimentDecorator {
    Beverage beverage; //被裝飾者

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

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

    public Double cost() {
        return 66.66 + beverage.cost();
    }
}
package decorator;

/**
 * <p>ClassName      TestDecorator
 * <p>Description    測試類
 * <p>Author         ChongLou
 * <p>Version
 * <p>Date           2017/7/24 1:09
 */
public class TestDecorator {
    public static void main(String[] args) {
        /**
         * 一杯Espresso,不加配料
         */
        Beverage beverage = new Espresso();
        System.out.println( beverage.getDescription() + " $" + beverage.cost() );

        /**
         * 一杯Houseblend,加Mocha,Whip
         */
        Beverage beverage1 = new HouseBlend();
        beverage1 = new Mocha( beverage1 );
        beverage1 = new Whip( beverage1 );
        System.out.println( beverage1.getDescription() + " $" + beverage1.cost() );
    }
}

運行結果

這裏寫圖片描述

總結

     又get一種新的pattern。

    裝飾者模式比繼承更加靈活機動,但是不要忘記了裝飾者模式的別名warpper,如果過度使用,多層warpper,會使程序變得很複雜。

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