从咖啡谈装饰模式

问题描述

    星巴克要订做一个管理系统.他们的咖啡有不同的品牌,latte(拿铁),卡布奇诺(cappuccino)等等当然以后肯定会改变,同时各种咖啡都可以加上milk(牛奶),soy(豆浆),sugar()等配料,当然配料也会改变(一杯咖啡可以加两分牛奶).还有咖啡有大杯小杯.

版本一

一个coffee父类,各种品牌的开发继承之. 语言是苍白的 看代码!

public class Coffee {
    private String description;      //品牌描述
    private String size;            
    private int milk;
    private int sugar;
    
    public Coffee(){                 //构造函数
        description="unknow coffee";
        size="small";
    }
    public Coffee(int milk,int sugar,String size,String brand){
        this.milk=milk;
        this.sugar=sugar;
        this.size=size;
        description=brand;
    }
    public String getDescription(){
         return description+"  "+size+"杯咖啡   milk:"+milk+"份    sugar:"+sugar+"份";        

    }
    public  double cost(){
        if(size.equals("small"))                   //小杯大杯分开
            return milk*1.1+sugar*1.2;
        if(size.equals("jourm"))
            return milk*1.2+sugar*1.4;
        return 0;
    }
}

然后就是一个拿铁(iatte)继承了coffee 别的品牌都一样的
public class iatte1 extends Coffee{
	public double cost(){
		return super.cost()+2.5;
	}
	
	public iatte1(int milk,int sugar,String size) {
		super(milk, sugar, size, "iatte");
	}
}
再看测试类
import condiment.*;
import base.Beverage;
import brand.*;

public class test {
	public static void main(String[] args){
	    Coffee aCoffee=new iatte1(2,3,"small");
	    System.out.println(aCoffee.getDescription());
            System.out.println(aCoffee.cost());
	}
}
测试结果
iatte  small杯咖啡   milk:2份    sugar:3份
8.3

大家可以看出来 关键的cost()计算和getdescription 都是在父类中完成的.
这样看起来还不错 不过真的不错吗?

几个问题

1:一旦我要更改某一种调料的价格怎么办?
2:我要新增一种调料怎么办?
3:如果有了新的饮料,如茶,问题是茶不会加奶呀 怎么办?

分析这个三个问题
其中1,2违反了开闭原则.第三个的设计也不合适
.
此时我们看看 装饰模式是怎么解决这个问题的.

装饰模式版本

我们建立一个抽象类beverage.
package base;
public abstract class Beverage {
public String description="unknow coffee";
public String size="unknow size";
public void setDescription(String description) {
this.description = description;
}

public String getDescription() {
return description;
}

    public abstract double cost();
}


让所有的咖啡品牌都继承beverage.
package brand;
import base.Beverage;


public class latte extends Beverage{
    public double cost() {
        if(size.endsWith("jorum"))
            return 1.5;
        else if(size.endsWith("small"))
            return 1.2;
        return 1.2;
            
    }
    public latte(){
        size="jorum";
        description="latte jorum coffee";
    }
    public latte(String size2){
        size=size2;
        description="latte "+size+" coffee";
    }
}
其他品牌类似,不在赘述.
   再建立一个所有调料(milk.soy等等)的基类condiment,并让它继承beverage.
package condiment;
import base.Beverage;


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

 
 然后所有的配料继承condiment.
package condiment;
import base.Beverage;


public class sugar extends condiment {

	Beverage beverage;
	public sugar(Beverage beverage2){
		beverage=beverage2;
	}
	
	public String getDescription() {
		System.out.print("suga 的形容  \n");
		return beverage.getDescription()+" ,sogar";
	}

	public double cost() {
		return beverage.cost()+2.4;
	}
}


  其他配料如milk等似,不在赘述.

uml图如下(取自head first design pattern )



   看看测试类.
import condiment.*;
import base.Beverage;
import brand.*;

public class test {
	public static void main(String[] args){
		System.out.println("第一杯");
		Beverage aBeverage=new latte();
		System.out.println(aBeverage.getDescription());
		System.out.println(aBeverage.cost());
		System.out.println(); 
		
		System.out.println("第二杯");		
		Beverage bBeverage=new cappuccino("small");
		bBeverage=new milk(bBeverage);
		bBeverage=new milk(bBeverage);
		bBeverage=new sugar(bBeverage);
		System.out.println(bBeverage.getDescription());
		System.out.println(bBeverage.cost());

	}
}

大家看看,在第二杯的时候,我们给咖啡加糖,加牛奶就new一个牛奶,new一个糖然后加进去很形象不是吗?

测试结果

第一杯
latte jorum coffee
1.5

第二杯
suga 的形容  
milk 的形容
milk 的形容
cappuccino small coffee,milk,milk ,sogar
6.1

这里有一个问题,这个小杯的含两份牛奶一份糖的cappuccino的价格到底是怎么算出来的呢?

 public double cost() {
        return beverage.cost()+2.4;
    }

这是糖的cost 。

看咱们的测试代码。Cappuccino最“外边”包的是糖,当我们调用bBeverage.cost()的时候,其实就是用糖的cost。Ok,看上面糖的cost,2.4+beverage.cout()这句代码里的beverage指的是谁呢?
bBeverage=new milk(bBeverage); 
bBeverage=new milk(bBeverage); 
bBeverage=new sugar(bBeverage);
很显然是牛奶。所以再调用牛奶的cost!继续往上走,所以的问题都解决了。其实我建议朋友们再看这部分的时候最好开启debug模式。亲自一步一步调试一下就解决问题了。
下图来自head first 里面的咖啡例子

 whip,mocha都是配料和本例子中的sugar.milk是一回事.darkroast是咖啡的品牌 相当于本例中的卡布奇诺,拿铁.

在javaio中的应用

http://blog.csdn.net/dlf123321/article/details/41348305

参考资料

<Head First Design Pattern>>




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值