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


/**//*
* Beverage是一個(gè)抽象類,有兩個(gè)方法
*/

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

/**//*
* getDescription()已經(jīng)在此實(shí)現(xiàn)了,但是cost()必須在子類中實(shí)現(xiàn)
*/

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

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


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

public abstract class CondimentDecorator extends Beverage
{

//所有的調(diào)料裝飾者都必須重新實(shí)現(xiàn)getDescription()方法.
public abstract String getDescription();
}

2.飲料實(shí)現(xiàn)
(1)Espresso
Espresso.java
package com.sterning.ch3_decorator;


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

public abstract class CondimentDecorator extends Beverage
{

//所有的調(diào)料裝飾者都必須重新實(shí)現(xiàn)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.調(diào)料實(shí)現(xiàn)
(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能夠引用一個(gè)Beverage,做法如下:一是用一個(gè)實(shí)例變量記錄飲料,也就是被裝飾者.
* 二是想辦法讓裝飾者(飲料)記錄到實(shí)例變量中,即把飲料當(dāng)作構(gòu)造器的參數(shù),再由構(gòu)造器將此飲料記錄在實(shí)例變量中
*/
Beverage beverage;


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

@Override

public String getDescription()
{

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

public double cost()
{

/**//*
* 要計(jì)算帶Mocha飲料的價(jià)錢,首先把調(diào)用委托給裝飾對象,以計(jì)算價(jià)錢,然后再加上Mocha的價(jià)錢,得到最后結(jié)果
*/
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,不需要調(diào)料,打印出它的描述和價(jià)錢.
*/
Beverage beverage=new Espresso();
System.out.println(beverage.getDescription()+" $"+beverage.cost());

/**//*
* 制造一個(gè)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());

/**//*
* 最后,再來一杯調(diào)料為豆?jié){,摩卡\奶泡的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