《Head First》第三節 裝飾者模式

背景介紹:星巴茲是一家很火爆的咖啡連鎖店,因爲擴張很快,需求多樣化,原系統已不能滿足。

原系統設計:


購買咖啡時,會要求加各種調料,系統要根據加的不同調料收取不同的費用,導致結構圖如下:


解決方案:

以飲料爲主體,然後運行時,以調料來“裝飾”(decorate)飲料。

比如,顧客要加摩卡和奶泡的深焙咖啡。那麼要做的是:

1.拿一個深焙咖啡(DarkRoast)對象

2.以摩卡(Mocha)對象裝飾它

3.以奶泡(Whip)對象裝飾它

4.調用cost()方法,並依賴委託(delegate)將調料的價錢加上去。

創建的圖如下:


結算時,最外圈裝飾者(Whip)的cost()就可以得到:


裝飾者模式類圖:


參照此類圖,得到星巴茲飲料類圖:


具體實現代碼:

Beverage(飲料)

public abstract class Beverage {
    public String description = "Unknown Beverage";

    public String getDescription() {
        return description;
    }

    public abstract double cost();
}

裝飾者類,Condiment(調料)

public abstract class CondimentDecorator extends Beverage {
    public abstract String getDescription();
}


各種飲料

HouseBlend(綜合咖啡)
public class HouseBlend extends Beverage {
    public HouseBlend() {
        description = "HouseBlend";
    }

    public double cost() {
        return .89;
    }
}
Espresso(濃縮咖啡)
public class Espresso extends Beverage {
    public Espresso() {
        description = "Espresso";
    }

    public double cost() {
        return 1.99;
    }
}
Decaf(低咖啡因)
public class Decaf extends Beverage {
    public Decaf() {
        description = "Decaf";
    }

    public double cost() {
        return 1.05;
    }
}
DarkRoast(深焙咖啡)
public class DarkRoast extends Beverage {
    public DarkRoast() {
        description = "DarkRoast";
    }

    public double cost() {
        return .99;
    }
}

各種調料

Mocha(摩卡)
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 beverage.cost() + .20;
    }
}
Soy(豆漿)
public class Soy extends CondimentDecorator {
    Beverage beverage;

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

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

    public double cost() {
        return beverage.cost() + .30;
    }
}
Whip(牛奶)
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 beverage.cost() + .30;
    }
}

測試:

public class StarbuzzCoffee {
    public static void main(String[] args) {
        Beverage beverage = new Espresso();
        System.out.println(beverage.getDescription() + " $" + beverage.cost());
        Beverage beverage1 = new Mocha(new Mocha(new Whip(new DarkRoast())));
        System.out.println(beverage1.getDescription() + " $" + beverage1.cost());
        Beverage beverage2 = new Soy(new Mocha(new Whip(new DarkRoast())));
        System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
    }
}

運行結果:



Java I/O流中的裝飾者模式


編寫自己的I/O裝飾者,實現大小寫轉換

public class LowerCaseInputStream extends FilterInputStream {
    public LowerCaseInputStream(InputStream in) {
        super(in);
    }

    public int read() throws IOException {
        int c = super.read();
        return (c == -1 ? c : Character.toLowerCase((char)c));
    }

    public int read(byte b[], int off, int len) throws IOException {
        int result = super.read(b, off, len);
        for (int i = off; i < off + result; i++) {
            b[i] = (byte) Character.toLowerCase((char)b[i]);
        }
        return result;
    }
}

測試

public class InputTest {
    public static void main(String[] args) {
        int c;
        try {
            InputStream is = new LowerCaseInputStream(new BufferedInputStream(new FileInputStream("test.txt")));
            while ((c = is.read()) >= 0) {
                System.out.print((char)c);
            }
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

運行結果


總結:

裝飾者模式--動態的將責任附加到對象上,想要擴展功能,裝飾者提供有別於繼承的另一種選擇。

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