Head First Java 设计模式——装饰者模式

        装饰者模式,动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更具有弹性的替代方案。书中给出的是一个星巴兹的实例,他们准备更新订单系统,原先的类设计如下:

现在要实现,当客户购买咖啡时,可以要求加入各种调料,例如Milk、Soy、Mocha等,然后加入的调料会收取不同的费用。我们可能会按如下方法去尝试:

 

为每一种咖啡都建一个类,但是这样就会出现"类爆炸"的问题了。于是你可能想到要通过修改Beverage:

	public abstract class Beverage {
		String description = "Unknown Beverage";
		boolean milk;
		boolean soy;
		boolean mocha;
		boolean whip;
		
		public boolean hasMilk();
		public void setMilk();
		public boolean hasSoy();
		public void setSoy();
		public boolean hasMocha();
		public void setMocha();
		public boolean hasWhip();
		public void setWhip();

		public String getDescription() {
			return description;
		}
		
		public double cost();
	}

这个时候cost()不是一个抽象方法,让它计算要加入的各种调料的价钱,然后子类仍将覆盖cost(),但是会调用超类的cost(),计算出基本饮料加上调料的价钱。但是这样又会出现几个问题:

1、一旦出现新的调料,我们就要加上新的方法,并改变超类的cost()方法。

2、以后可能会开发出新饮料,新的饮料某些调料可能不适合,但是这个设计方式,新的子类仍将要继承那些不适合的方法。

3、万一顾客想要双倍摩卡咖啡呢。

 

 

 

 

        下面采用新的方法:以饮料为主题,然后在运行时以调料来“装饰”饮料。用代码的方式呈现如下:

先从Beverage类下手:

	public abstract class Beverage {
		String description = "Unknown Beverage";
		
		public String getDescription() {
			return description;
		}
		
		public abstract double cost();
	}

然后实现Condiment(调料)抽象类,也就是装饰者类:

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

接下来写饮料的代码,例如浓缩咖啡(Espresso),家常咖啡(HouseBlend):

	public class Espresso extends Beverage {
		public Espresso() {
			description = "Espresso";
		}
		public double cost() {
			return 1.99;
		}
	}
	
	public class HouseBlend extends Beverage {
		public HouseBlend() {
			description = "House Blend Coffee";
		}
		public double cost() {
			return 0.89;
		}
	}

写调料代码,例如摩卡(Mocha):

	public class Mocha extends CondimentDecorator {
		Beverage beverage;
		
		public Mocha(Beverage beverage) {
			this.beverage = beverage;
		}
		
		public String getDescription() {
			return beverage.getDescription() + ", Mocha";
		}
		
		public double cost() {
			//这里计算带Mocha饮料的价钱,先把调用委托给被装饰对象,再加上Mocha的价钱,得到最终结果。
			return 0.20 + beverage.cost();
		}
	}

 最后,我们可以通过下面的方式来使用:

public class StarBuzzCoffee {
		public static void main(String args[]) {
			//订一杯Espresso,不需要调料。
			Beverage beverage = new Espresso();
			System.out.println(beverage.getDescription() + "$" + beverage.cost());
			
			//订一杯DarkRost咖啡。
			Beverage beverage2 = new DarkRost();
			//用Mocha装饰它。
			beverage2 = new Mocha(beverage2);
			//用第二个Mocha装饰它。
			beverage2 = new Mocha(beverage2);
			//用Whip装饰它。
			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());
		}
	}


 

这一章提到的设计原则:

1、开放-关闭原则(类应该对扩展开放,对修改关闭)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值