Posted on 2008-01-21 10:05
詩特林 閱讀(4326)
評論(2) 編輯 收藏 所屬分類:
DesignPattern
【Head First設計模式】-Decorator模式
一、要完成的任務
星巴茲(Starbuzz)是以擴張速度最快而聞名的咖啡連鎖店。如果你在街角看到它的店,在對面街上肯定還會看到另一家。因為擴張速度實在太快了,他們準備更新訂單系統,以合乎他們的飲料供應要求。他們原先的類設計是這樣的……
購買咖啡時,也可以要求在其中加入各種調料,例如:蒸奶(Steamed Milk)、豆漿(Soy)、摩卡(Mocha,也就是巧克力風味)或覆蓋奶泡。星巴茲會根據所加入的調料收取不同的費用。所以訂單系統必須考慮到這些調料部分。
二、Decorator模式
1、一個原則
類應該對擴展開放,對修改關閉
2、定義裝飾者模式
裝飾者模式動態地將責任附加到對象上。若要擴展功能,裝飾者提供了比繼承更有彈性的替代方案。
3.分析任務
4.設計任務
三、代碼實現
1.定義抽象類
(1)飲料抽象類Beverage
Beverage.java
package com.sterning.ch3_decorator;


/**//*
* Beverage是一個抽象類,有兩個方法
*/

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

/**//*
* getDescription()已經在此實現了,但是cost()必須在子類中實現
*/

public String getDescription()
{
return description;
}
public abstract double cost();
}

(2)調料抽象類CondimentDecorator
CondimentDecorator.java
package com.sterning.ch3_decorator;


/**//*
* 首先,必須讓CondimentDecorator能夠取代Beverage,所以將CondimentDecorator擴展自Beverage類
*/

public abstract class CondimentDecorator extends Beverage
{

//所有的調料裝飾者都必須重新實現getDescription()方法.
public abstract String getDescription();
}

2.飲料實現
(1)Espresso
Espresso.java
package com.sterning.ch3_decorator;


/**//*
* 首先,必須讓CondimentDecorator能夠取代Beverage,所以將CondimentDecorator擴展自Beverage類
*/

public abstract class CondimentDecorator extends Beverage
{

//所有的調料裝飾者都必須重新實現getDescription()方法.
public abstract String getDescription();
}

(2)HouseBlend
HouseBlend.java
package com.sterning.ch3_decorator.drink;

import com.sterning.ch3_decorator.Beverage;


public class HouseBlend extends Beverage
{

public HouseBlend()
{
description="House Blend Coffee";
}

@Override

public double cost()
{
return 0.89;
}

}

(3)DarkRoast
DarkRoast.java
package com.sterning.ch3_decorator.drink;

import com.sterning.ch3_decorator.Beverage;


public class DarkRoast extends Beverage
{

public DarkRoast()
{
description="Dark Roast Coffee";
}

@Override

public double cost()
{
return 0.99;
}
}

(4)Decaf
Decaf.java
package com.sterning.ch3_decorator.drink;

import com.sterning.ch3_decorator.Beverage;


public class Decaf extends Beverage
{

public Decaf()
{
description="Decaf Coffee";
}

@Override

public double cost()
{
return 1.05;
}
}

3.調料實現
(1)Mocha
Mocha.java
package com.sterning.ch3_decorator.condiment;

import com.sterning.ch3_decorator.Beverage;
import com.sterning.ch3_decorator.CondimentDecorator;


public class Mocha extends CondimentDecorator
{

/**//*
* 要讓Mocha能夠引用一個Beverage,做法如下:一是用一個實例變量記錄飲料,也就是被裝飾者.
* 二是想辦法讓裝飾者(飲料)記錄到實例變量中,即把飲料當作構造器的參數,再由構造器將此飲料記錄在實例變量中
*/
Beverage beverage;


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

@Override

public String getDescription()
{

/**//*
* 我們希望敘述不只是描述飲料,而是完整的連調料都描述出來
*/
return beverage.getDescription()+",Mocha";
}
@Override

public double cost()
{

/**//*
* 要計算帶Mocha飲料的價錢,首先把調用委托給裝飾對象,以計算價錢,然后再加上Mocha的價錢,得到最后結果
*/
return 0.20+beverage.cost();
}
}

(2)Soy
Soy.java
package com.sterning.ch3_decorator.condiment;

import com.sterning.ch3_decorator.Beverage;
import com.sterning.ch3_decorator.CondimentDecorator;


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 .15 + beverage.cost();
}
}

(3)Whip
Whip.java
package com.sterning.ch3_decorator.condiment;

import com.sterning.ch3_decorator.Beverage;
import com.sterning.ch3_decorator.CondimentDecorator;

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 .10 + beverage.cost();
}
}

4.測試類StarbuzzCoffee
StarbuzzCoffee.java
package com.sterning.ch3_decorator;

import com.sterning.ch3_decorator.condiment.Mocha;
import com.sterning.ch3_decorator.condiment.Soy;
import com.sterning.ch3_decorator.condiment.Whip;
import com.sterning.ch3_decorator.drink.DarkRoast;
import com.sterning.ch3_decorator.drink.Espresso;
import com.sterning.ch3_decorator.drink.HouseBlend;


public class StarbuzzCoffee
{

public static void main(String args[])
{

/**//*
* 訂一杯Espresso,不需要調料,打印出它的描述和價錢.
*/
Beverage beverage=new Espresso();
System.out.println(beverage.getDescription()+" $"+beverage.cost());

/**//*
* 制造一個DarkRoast對象,用Mocha,Whip裝飾它
*/
Beverage beverage2=new DarkRoast();
beverage2=new Mocha(beverage2);
beverage2=new Mocha(beverage2);
beverage2=new Whip(beverage2);
System.out.println(beverage2.getDescription()+" $"+beverage2.cost());

/**//*
* 最后,再來一杯調料為豆漿,摩卡\奶泡的HouseBlend咖啡
*/
Beverage beverage3=new HouseBlend();
beverage3=new Soy(beverage3);
beverage3=new Mocha(beverage3);
beverage3=new Whip(beverage3);
System.out.println(beverage3.getDescription()+" $"+beverage3.cost());
}
}

源代碼下載:ch3_decorator.rar