Java设计模式----------装饰者模式

注:本篇博客内容出自Head First设计模式,仅对文章进行整理与总结。


1. 问题引出

我们需要为一家咖啡店做一套新的订单系统,之前的设计如下图所示:

另外购买咖啡时还需要加入不同的调料,如蒸奶(Steamed Milk),豆浆(Soy),摩卡(Mocha)或者是奶泡并收取不同的费用等。

如果我们列出不同的搭配方案供客户选择,那么难以想象我们最终需要列出多少具体类,这也违反了我们之前的设计原则:针对接口编程,而不是针对具体实现编程。

还有一种实现就是使用成员变量和继承去追踪添加的不同调料,看下图:

如果按照这种方法实现,那么今后如果添加新的调料或者修改现有调料价格亦或是其他操作,我们就必须打开Beverage或者其子类修改代码,这样就会使得代码难以维护。


2 解决思路

我们的目标是允许类容易拓展,在不修改现有代码的情况下,就可以搭配新的行为,此例中就是搭配不同的调料。这样的设计具有弹性可以应对改变,可以接受新的功能来应对。

至此,我们引入一个新的设计原则:开放-关闭原则,即:

类应该对扩展开放,对修改关闭

简单来说就是对于已经设计好的类,不应该再去修改它,但是我们可以扩展它。举个不恰当的列子,比如之前的观察者模式中,我们对于Object的实现类,在运行时可以任意添加和删除Observer而不需要修改具体类。

对于现在的情况,我们需要计算咖啡和不同调料的价格来计算出饮品的售价。根据上面的原则,我们需要在运行时将不同的调料加入到咖啡中,而不是在程序运行前去修改具体的饮品类。

策略模式中,我们利用组合和委托的方式,在运行时动态的赋予子类不同的行为,达到了类似继承的效果。利用继承的方式设计子类时,子类的行为是在运行前静态决定的,如果使用组合和委托就可以在运行时动态的扩展子类的行为,达到想要的效果。

所以,我们可以将咖啡和调料分为两大类族,这样就可以程序运行时指定特定的行为(调料)。


3 装饰者模式

下面是按照装饰者模式制作的一份摩卡加奶泡的深焙咖啡:

(1)拿一个深焙咖啡:

(2)以摩卡对象装饰它


(3)以奶泡对象装饰它

(4)最后计算价格


接下来实际写一些代码来实现上述流程。

再此之前先看一下观察者模式的定义和整体的设计框架。

观察者模式定义如下:

动态的将责任附加到对象身上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。


整体设计框架如下:


从上图中我们看到CondimentDecorator类继承了Beverage,这里的继承是为了达到类型匹配的效果,而不是利用继承获得行为,且装饰者和被装饰者必须有想同的接口,这是因为装饰者必须能取代被装饰者,这个看代码会理解的深刻一些。下面开始写一些代码。


4 代码实现

1. 首先是父类Beverage:
/**
 * This class use as base class of different beverage
 * @author canvas
 *
 */
public abstract class Beverage {
	protected String description = "Unknow beverage";
	
	public String getDescription() {
		return description;
	}
	
	public abstract double cost();
}
2. 接下来是调料抽象类CondimentDecorator:
public abstract class CondimentDecorator extends Beverage{
	public abstract String getDescription();
}
3.具体的Beverage子类:
//Espresso类
public class Espresso extends Beverage {

	public Espresso() {
		// TODO Auto-generated constructor stub
		description = "Espresso";
	}
	
	@Override
	public double cost() {
		// TODO Auto-generated method stub
		return 1.99;
	}

}

//HouseBlend类
public class HouseBlend extends Beverage {

	public HouseBlend() {
		// TODO Auto-generated constructor stub
		description = "HouseBlend";
	}
	
	@Override
	public double cost() {
		// TODO Auto-generated method stub
		return 0.89;
	}

}

//.....其他类省略,可自行实现

4. 具体的调料子类:
public class Mocha extends CondimentDecorator {
	private Beverage beverage;
	
	public Mocha(Beverage beverage) {
		// TODO Auto-generated constructor stub
		this.beverage = beverage;
	}
	
	@Override
	public String getDescription() {
		// TODO Auto-generated method stub
		return beverage.getDescription()+" , Mocha";
	}

	@Override
	public double cost() {
		// TODO Auto-generated method stub
		return beverage.cost()+0.20;
	}

}


public class Soy extends CondimentDecorator {
	private Beverage beverage;
	
	public Soy(Beverage beverage) {
		// TODO Auto-generated constructor stub
		this.beverage = beverage;
	}
	
	@Override
	public String getDescription() {
		// TODO Auto-generated method stub
		return beverage.getDescription()+" , Soy";
	}

	@Override
	public double cost() {
		// TODO Auto-generated method stub
		return beverage.cost()+0.30;
	}

}


public class Whip extends CondimentDecorator {
	private Beverage beverage;
	
	public Whip(Beverage beverage) {
		// TODO Auto-generated constructor stub
		this.beverage = beverage;
	}
	
	@Override
	public String getDescription() {
		// TODO Auto-generated method stub
		return beverage.getDescription()+" , Whip";
	}

	@Override
	public double cost() {
		// TODO Auto-generated method stub
		return beverage.cost()+0.80;
	}

}

5. 测试代码:
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Beverage beverage = new Espresso();
		System.out.println(beverage.getDescription()+" , cost : "+beverage.cost());
		
		Beverage beverage2 = new HouseBlend();
		beverage2 = new Mocha(beverage2);
		beverage2 = new Mocha(beverage2);
		beverage2 = new Whip(beverage2);
		System.out.println(beverage2.getDescription()+" , cost : "+beverage2.cost());
		
		Beverage beverage3 = new Espresso();
		beverage3 = new Mocha(beverage3);
		beverage3 = new Soy(beverage3);
		beverage3 = new Whip(beverage3);
		
		System.out.println(beverage3.getDescription()+" , cost : "+beverage3.cost());
	}

6. 输出结果
Espresso , cost : 1.99
HouseBlend , Mocha , Mocha , Whip , cost : 2.09
Espresso , Mocha , Soy , Whip , cost : 3.29

以上,结束。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值