【Head First設計模式】-Decorator模式

原文:http://www.blogjava.net/sterning/archive/2008/01/21/176679.html

一、要完成的任務

星巴茲(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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章