裝飾者模式

需求

咖啡店,客戶可能會叫一種飲料,并且指定某些調(diào)料加入進去,比如深焙咖啡,用摩卡,奶泡,牛奶作為調(diào)料,計算出總價

飲料類,被裝飾者

/**
 * 飲料父類
 */
public abstract class Beverage
{
    /**
     * 描述飲料的字段
     */
    protected String description = "Unknown Berverage";

    public String getDescription()
    {
        return description;
    }

    /**
     * 計算價錢的方法,必須在子類中實現(xiàn)
     */
    public abstract double cost();
}

/**
 * 暗烤咖啡
 */
public class DarkRoast extends Beverage
{
    public DarkRoast()
    {
        description = "暗烤咖啡 DarkRoast"; // 描述此飲料
    }

    /**
     * 返回此飲料的價錢
     */
    @Override
    public double cost()
    {
        return .99;
    }
}

調(diào)料類,裝飾者

/**
 * 調(diào)料類,也就是裝飾者
 * 
 * 為了讓 裝飾者 能夠替代 被裝飾者 ,因此 裝飾者 繼承 被裝飾者
 */
public abstract class Condiment extends Beverage
{
    /**
     * 所有的裝飾者類,都必須重新實現(xiàn)此方法,因為必須有不同的名稱
     */
    @Override
    public abstract String getDescription();
}

/**
 * 摩卡調(diào)料
 */
public class Mocha extends Condiment
{
    private Beverage beverage; // 用來記住 被裝飾者 ,也就是此調(diào)料要加在哪個飲料上

    /**
     * 想辦法把被裝飾者記錄在變量中
     */
    public Mocha(Beverage beverage)
    {
        this.beverage = beverage;
    }

    /**
     * 把被裝飾者和裝飾者的名稱組合起來,比如:混合咖啡,摩卡
     */
    @Override
    public String getDescription()
    {
        return beverage.getDescription() + ", 摩卡調(diào)料 Mocha";
    }

    /**
     * Mocha自身的價錢+飲料的價錢
     */
    @Override
    public double cost()
    {
        return 0.20 + beverage.cost();
    }
}

/**
 * 豆奶調(diào)料
 */
public class Soy extends Condiment
{
    private Beverage beverage;

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

    @Override
    public String getDescription()
    {
        return beverage.getDescription() + ", 豆奶調(diào)料 Soy";
    }

    @Override
    public double cost()
    {
        return .15 + beverage.cost();
    }
}

測試

// 點一杯飲料
Beverage beverage2 = new DarkRoast();
// 用調(diào)料去裝飾飲料
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
// 算出總價錢
System.out.println(beverage2.getDescription() + " $" + beverage2.cost());

疑問

  • 以上全用了繼承,這里是利用繼承達到類型匹配的目的,并不是獲得行為。方便更有彈性的混合匹配
  • 每當(dāng)需要新的調(diào)料,甚至是新的飲料,都可以新增并方便的加入
  • 并非一定要用接口,如果抽象類用的好好的,并且已經(jīng)滿足需求,就不用再去修改他
  • 會導(dǎo)致有很多的小類

Java 中應(yīng)用到裝飾者模式的地方

Java I/O

設(shè)計原則 5

類應(yīng)該對擴展開放,對修改關(guān)閉,在不修改現(xiàn)有代碼的情況下,就搭配新的行為

裝飾者模式定義:

動態(tài)的將責(zé)任附加到對象上,對于擴展的話,比繼承更有彈性。

?著作權(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ù)。

相關(guān)閱讀更多精彩內(nèi)容

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