裝飾者模式

星巴克咖啡訂單項目

咖啡館:
一、咖啡種類/單品咖啡:Espresso(意大利濃咖啡)、ShortBlack、LongBlack(美式咖啡)、Decaf(無因咖啡);
二、調料:Milk、Soy(豆漿)、Chocolate;
三、要求在擴展新的咖啡種類時,具備良好的擴展性、改動方便、維護方便;
四、使用OO的來計算不一樣種類咖啡的費用:客戶能夠點單品咖啡,也能夠單品咖啡+調料組合。java

常規思路

一、Drink是一個抽象類,表示飲料;
二、description就是對咖啡的描述,好比咖啡的名字;
三、cost()方法就是計算費用,Drink類中作成一個抽象方法;
四、Decaf就是單品咖啡,繼承Drink,並實現cost;
五、Espress && Milk就是單品咖啡+調料,這個組合不少;
存在的問題是:這樣設計,會有不少類,當咱們增長一個單品咖啡,或者一個新的調料,類的數量就會倍增,就會出現類爆炸。ide

解決方案:將調料內置到Drink類中,避免類爆炸

常規思路的解決方案由於咖啡單品+調料組合會形成類的倍增,所以能夠作改進,將調料內置到Drink類,這樣就不會形成類數量過多。從而提升項目的維護性(如圖):this

說明:milk,soy,chocolate能夠設計爲Boolean,表示是否要添加相應的調料。設計

將調料內置到Drink類中的解決方案能夠控制類的數量,不至於形成不少的類。可是,在增長或者刪除調料種類時,代碼的維護量很大。考慮到用戶能夠添加多份調料時,能夠將hasMilk返回一個對應int。3d

針對當前這個問題,能夠考慮使用裝飾者模式。code

裝飾者模式

基本定義

一、裝飾者模式:動態的將新功能附加到對象上。在對象功能擴展方面,它比繼承更有彈性,裝飾者模式也體現了開閉原則(ocp);
二、這裏提到的動態的將新功能附加到對象ocp原則,在後面的應用實例上會以代碼的形式體現。對象

裝飾者原理

一、裝飾者模式就像打包一個快遞
主體:好比:陶瓷、衣服(Component) //被裝飾者;
包裝:好比:報紙填充、塑料泡沫、紙板、木板(Decorator);
二、Component(主體):好比相似前面的Drink;blog

三、ConcreteComponent和Decorator
ConcreteComponent:具體的主體,好比前面的各個單品咖啡;繼承

Decorator:裝飾者,好比各調料;
四、在如圖的Component與ConcreteComponent之間,若是ConcreteComponent類不少,還能夠設計一個緩衝層,將共有的部分提取出來,抽象層一個類。遞歸

裝飾者模式解決咖啡訂單需求

例如,裝飾者模式下的訂單:2份巧克力+一份牛奶的LongBlack。

說明:
一、Milk包含了LongBlack;
二、一份Chocolate包含了(Milk+LongBlack);
三、一份Chocolate包含了(Chocolate+Milk+LongBlack);
這樣無論是什麼形式的單品咖啡+調料組合,經過遞歸方式能夠方便的組合和維護。

Codes

一、飲品抽象類

@Getter
@Setter
public abstract class Drink {

    public String des; // 描述
    private float price = 0.0f;
    
    //計算費用的抽象方法
    //子類來實現
    public abstract float cost();
}

二、咖啡類

咖啡類:

public class Coffee  extends Drink {

    @Override
    public float cost() {
        return super.getPrice();
    }
}

無因咖啡:

public class DeCaf extends Coffee {

    public DeCaf() {
        setDes(" 無因咖啡 ");
        setPrice(1.0f);
    }
}

意大利咖啡:

public class Espresso extends Coffee {

    public Espresso() {
        setDes(" 意大利咖啡 ");
        setPrice(6.0f);
    }
}

LongBlack:

public class LongBlack extends Coffee {

    public LongBlack() {
        setDes(" longblack ");
        setPrice(5.0f);
    }
}

ShortBlack:

public class ShortBlack extends Coffee{

    public ShortBlack() {
        setDes(" shortblack ");
        setPrice(4.0f);
    }
}

三、裝飾者類

裝飾者父類:

public class Decorator extends Drink {
    private Drink obj;

    public Decorator(Drink obj) { //組合
        this.obj = obj;
    }

    @Override
    public float cost() {
        // getPrice 本身價格
        return super.getPrice() + obj.cost();
    }

    @Override
    public String getDes() {
        // obj.getDes() 輸出被裝飾者的信息
        return des + " " + getPrice() + " && " + obj.getDes();
    }
}

具體的裝飾類,巧克力:

//具體的Decorator, 這裏就是調味品
public class Chocolate extends Decorator {

    public Chocolate(Drink obj) {
        super(obj);
        setDes(" 巧克力 ");
        setPrice(3.0f); // 調味品 的價格
    }
}

具體的裝飾類,牛奶:

public class Milk extends Decorator {
    public Milk(Drink obj) {
        super(obj);
        setDes(" 牛奶 ");
        setPrice(2.0f);
    }
}

具體的裝飾類,豆漿:

public class Soy extends Decorator{
    public Soy(Drink obj) {
        super(obj);
        // TODO Auto-generated constructor stub
        setDes(" 豆漿  ");
        setPrice(1.5f);
    }
}

四、咖啡店

public class CoffeeBar {
    public static void main(String[] args) {
        // 裝飾者模式下的訂單:2份巧克力+一份牛奶的LongBlack

        // 1. 點一份 LongBlack
        Drink order = new LongBlack();
        System.out.println("費用1=" + order.cost());
        System.out.println("描述=" + order.getDes());

        // 2. order 加入一份牛奶
        order = new Milk(order);

        System.out.println("order 加入一份牛奶 費用 =" + order.cost());
        System.out.println("order 加入一份牛奶 描述 = " + order.getDes());

        // 3. order 加入一份巧克力

        order = new Chocolate(order);

        System.out.println("order 加入一份牛奶 加入一份巧克力  費用 =" + order.cost());
        System.out.println("order 加入一份牛奶 加入一份巧克力 描述 = " + order.getDes());

        // 3. order 加入一份巧克力

        order = new Chocolate(order);

        System.out.println("order 加入一份牛奶 加入2份巧克力   費用 =" + order.cost());
        System.out.println("order 加入一份牛奶 加入2份巧克力 描述 = " + order.getDes());

        System.out.println("===========================");

        Drink order2 = new DeCaf();

        System.out.println("order2 無因咖啡  費用 =" + order2.cost());
        System.out.println("order2 無因咖啡 描述 = " + order2.getDes());

        order2 = new Milk(order2);

        System.out.println("order2 無因咖啡 加入一份牛奶  費用 =" + order2.cost());
        System.out.println("order2 無因咖啡 加入一份牛奶 描述 = " + order2.getDes());
    }
}
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息