接上文。
我们知道,利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为。然而,如果能够利用组合的做法扩展对象的行为,就可以在运行时动态地进行扩展。
这里引出一个很重要的设计原则,开闭原则
设计原则
类应该对扩展开放,对修改关闭。
我们的目标是允许类容易扩展,在不修改现有代码的情况下,就可搭配新的行为。这样的设计具有弹性,可以应对改变,可以接收新的功能来应对改变的需求。
下面来看用装饰者模式是如何实现开闭原则的。
装饰者模式方案
我们已经了解利用继承无法完全解决问题,所以,这里采用不一样的做法:我们要以饮料为主体,然后在运行时以调料来装饰(decorate)饮料。比方说,如果顾客想要摩卡和奶泡深培咖啡,那么要做的是:
1、拿一个深培咖啡(DarkRoast)对象
2、以摩卡(Mocha)对象装饰它
3、以奶泡(Whip)对象装饰它
4、调用cost()方法,并依赖委托(delegate)将调料的价钱加上去。
代码展示,先从Beverage类下手,这不需要改变最原始的设计。
public abstract class Beverage {
String description = "Unknown Beverage";
public String getDescription() {
return desciption;
}
public abstract double cost();
}
调料抽象类Condiment,也就是装饰者类
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
饮料的代码
public class Espresso extends Beverage {
public Espresso() {
description = "Espresso";
}
public double cost() {
// 不需要管调料的价钱,直接把Espresso的价格返回即可。
return 1.99;
}
}
调料的代码
public class Mocha extends CondimentDecorator {
// 记录饮料,也就是被装饰者
Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
public double cost() {
return 0.20 + beverage.cost();
}
}
下订单的测试代码
public static void main(String args[]) {
// 订一个双倍摩卡奶泡深培
Beverage beverage = new DarkRoast();
beverage = new Mocha(beverage);
// 用第二个Mocha装饰它
beverage = new Mocha(beverage);
beverage = new Whip(beverage);
System.out.println(beverage.cost());
}
以上就是用装饰者模式实现的咖啡店的方案。看Java里哪些类实现了装饰者模式,请看《HeadFirst设计模式-装饰者模式(下)》