posts - 310, comments - 6939, trackbacks - 0, articles - 3
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

【Head First设计模式】-Decorator模式

Posted on 2008-01-21 10:05 诗特林 阅读(4317) 评论(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.饮料实现

 

1Espresso

Espresso.java

package com.sterning.ch3_decorator;

/*
 * 首先,必须让CondimentDecorator能够取代Beverage,所以将CondimentDecorator扩展自Beverage类
 
*/

public abstract class CondimentDecorator extends Beverage {

    
//所有的调料装饰者都必须重新实现getDescription()方法.
    public abstract String getDescription();
}


 

2HouseBlend

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;
    }


}

 

3DarkRoast

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;
    }

}

 

4Decaf

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.调料实现

1Mocha

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();
    }

}


 

2Soy

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();
    }

}


 

3Whip

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

评论

# re: 【Head First设计模式】-Decorator模式  回复  更多评论   

2008-08-01 11:32 by xue
好,好好

# re: 【Head First设计模式】-Decorator模式  回复  更多评论   

2008-08-11 12:08 by zx
(1)Espresso 代码贴错了

只有注册用户登录后才能发表评论。


网站导航: