善用设计模式-装饰者模式

本文整理自百度文库ppt:http://wenku.baidu.com/link?url=vWUj0YhlLr0C2X8s9tZ_UkZN9pUmgDQz2G7kCAiPLkP83HLaQBQtnSGrJQJ4typ-Av0tqetq-a6T6b7uPTq2_K17j0vGXcypoFCU32YT-dC

案例:星巴兹(Starbuzz)咖啡订购系统。

最初设计的订购系统如下图:


购买咖啡时,每一种咖啡中能添加一种或几种调料:steamed milk(蒸煮的牛奶), soy(酱油), mocha(摩卡,也称为巧克力),和 whipped milk (加了甜点心的牛奶)。每一种调料都要收一点钱,星巴兹(Starbuzz)咖啡订购系统变成下面的样子:


显然上面这种设计是不合理的,后面设计人员再次做了改动,修改后如下图


这个设计的缺陷
  如果调料的价格改变,我们需要修改现存的代码。
  如果增加了新的调料,我们需要在基类增加新的方法以及修改cost()方法。
  我们也可能有新的饮料类型。一些饮料类型,例如,冰茶(ice tea),现有的调料可能是不合适的。但是,茶子类仍然后继承基类的调料方法。
  如果客户需要双份mocha,怎么办呢?

我们已经看到:附加调料的饮料定价模式,用继承表示是不合适的;在基类增加调料的实例变量和方法,对一些子类也是不合适的。 这里,我们试试:以饮料为主体,用调料“装饰”饮料。例如,如果客户需要Dark Roast(焦炒咖啡) ,添加Mocha(摩卡)和Whip(甜点心)。

我们可以:
     取DarkRoast (焦炒咖啡)对象;
     用Mocha (摩卡)对象装饰它;
     用Whip (甜点心)对象装饰它;
     调用cost()方法计算价格,总价格的计算需要委托。
     但是,我们怎样装饰一个对象?又怎样委托?

装饰者模式,动态地给对象添加职责,就扩展功能而言,装饰者比派生子类提供了更好的柔性。




接下来我们看星巴克订购的实现代码:

/**
 * @author pengl
 * 2014-5-7
 * 描述:被装饰基类 (组件接口) 饮品
 */
public abstract class Beverage {
	protected String description; 
	/**
	 * 饮品描述信息
	 * @return
	 */
	protected String getDescription(){
		return description;
	}
	/**
	 * 计算价格
	 * @return
	 */
	protected abstract double cost();
}

/**
 * @author pengl
 * 2014-5-7
 * 描述:被装饰者子类(具体组件) 焦烤咖啡
 */
public class DarkRoast extends Beverage{
	public DarkRoast(){
		description = "焦烤咖啡";
	}
	@Override
	protected double cost() {
		return 2.5;
	}
}

/**
 * @author pengl
 * 2014-5-7
 * 描述:被装饰者子类(具体组件) 家庭混合咖啡
 */
public class HouseBlend extends Beverage{
	public HouseBlend(){
		description = "家庭混合咖啡";
	}
	@Override
	protected double cost() {
		return 1.8;
	}

}

/**
 * @author pengl
 * 2014-5-8
 * 描述:装饰者基类
 */
public abstract class CondimentDecorator extends Beverage{
	public abstract String getDescription();
}

/**
 * @author pengl
 * 2014-5-8
 * 描述:装饰者实现类  摩卡
 */
public class Mocha extends CondimentDecorator{
	
	Beverage beverage; 
	public Mocha(Beverage beverage){
		this.beverage = beverage;
	}
	@Override
	public String getDescription() {
		return beverage.getDescription() + ",Mocha";
	}
	@Override
	protected double cost() {
		return 0.7 + beverage.cost();
	}

}

/**
 * @author pengl
 * 2014-5-8
 * 描述:装饰者实现类  牛奶
 */
public class Milk extends CondimentDecorator{
	
	Beverage beverage; 
	public Milk(Beverage beverage){
		this.beverage = beverage;
	}
	@Override
	public String getDescription() {
		return beverage.getDescription() + ",Milk";
	}
	@Override
	protected double cost() {
		return 0.2 + beverage.cost();
	}
}

/**
 * @author pengl
 * 2014-5-8
 * 描述:客户端测试类
 */
public class Main {
	public static void main(String[] args) {
		Beverage beverage = new DarkRoast(); // 焦烤咖啡
		System.out.println(beverage.getDescription() + " $" + beverage.cost()); 
		beverage = new Mocha(beverage); //添加摩卡
		System.out.println(beverage.getDescription() + " $" + beverage.cost()); 
		beverage = new Milk(beverage);	//添加牛奶
		System.out.println(beverage.getDescription() + " $" + beverage.cost());
		Beverage beverage2 = new Milk(new HouseBlend()); // 家庭混合咖啡加摩卡加牛奶
		System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
	}
}

接下来我以我公司的业务写的一个测试装饰者模式代码

/**
 * @author pengl
 * 2014-5-9
 * 描述:客户端测试类
 */
public class Main {
	public static void main(String[] args) {
		IGetLoginInfo loginInfo = new GetLoginBasicInfo();
		//只要基本信息
		System.out.println(loginInfo.getLoginInfo().get("custName")+"--"+loginInfo.getLoginInfo().get("custId"));
		//要基本信息和套餐速率信息
		loginInfo = new GetLoginPackageAndSpeed(new GetLoginBasicInfo());
		System.out.println(loginInfo.getLoginInfo().get("custName")+"--"+loginInfo.getLoginInfo().get("custId")
				+"--"+loginInfo.getLoginInfo().get("speed")+"--"+loginInfo.getLoginInfo().get("package"));
		//要基本信息,套餐速率信息 和费用信息
		loginInfo = new GetLoginAccountBalance(new GetLoginPackageAndSpeed(new GetLoginBasicInfo()));
		System.out.println(loginInfo.getLoginInfo().get("custName")+"--"+loginInfo.getLoginInfo().get("custId")
				+"--"+loginInfo.getLoginInfo().get("speed")+"--"+loginInfo.getLoginInfo().get("package")
				+"--"+loginInfo.getLoginInfo().get("balance")+"--"+loginInfo.getLoginInfo().get("lastDate"));

	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值