装饰者模式可以使用对象组合的方式,做到在运行时装饰类,能够在不修改任何底层代码的情况下,给对象赋予新的职责。本章可以称为:给爱用继承的人一个全新的设计眼界。下面我们就来学习下这个模式。
场景描述
书中描述了一个制作饮料的场景,比如星巴克的咖啡,制作一杯咖啡可以加其他配料,而最终的价格会根据调料的不同而不同。装饰者模式的实现方式是以咖啡为基底,使用配料装饰器来装饰,最终形成的就是一杯我们需要的咖啡。概念说不太清楚,直接看下面代码会更直观。
代码示例
定义饮料抽象类
123456789public abstract class Beverage {String description = "Unknown Beverage";public String getDescription() {return description;}public abstract double cost();}定义调料装饰者抽象类,继承饮料
1234public abstract class CondimentDecorator extends Beverage {public abstract String getDescription();}定义咖啡实体类,继承饮料
12345678910111213public class HouseBlend extends Beverage {/*** 构造函数中指定咖啡的名称描述*/public HouseBlend() {description = "House Blend Coffee";}public double cost() {return 0.89;}}定义调料实体类,继承调料装饰者,装饰器中记录了被装饰者。Soy和Wip调料类似
12345678910111213141516171819202122232425public class Mocha extends CondimentDecorator {/*** 示例变量记录饮料,也就是被装饰者*/Beverage beverage;public Mocha(Beverage beverage) {this.beverage = beverage;}/*** 饮料加调料的完整描述** @return*/public String getDescription() {return beverage.getDescription() + ", Mocha";}public double cost() {return 0.20 + beverage.cost();}}测试
123456789public class Test {public static void main(String[] args) {Beverage houseBlend = new HouseBlend();houseBlend = new Syo(houseBlend);houseBlend = new Mocha(houseBlend);houseBlend = new Whip(houseBlend);System.out.println(houseBlend.getDescription() + " $ " + houseBlend.cost());}}
开始不太理解,看完代码之后,感受到这个模式的好处了,可以一层层装饰,无限叠加属性。其方法的调用方式有点类似递归,从description的打印可以看出,beverage一层层调用,从最后一个装饰器开始,一直调用到被装饰者的description方法。最先打印出需要装饰的主类的名称,然后是第一个装饰器,依次类推。另外一个重点在于,装饰者和被装饰者必须是一样的类型,也就是有共同的超类。这里使用了继承,但是是利用继承达到类型匹配,而不是利用继承来获得行为。
总结
装饰者模式的无限包装确实给我们一个全新的眼界,不能再局限于通过继承获得行为了。但是配料都继承饮料感觉有点怪怪的,又不能包装成别的类型。继续往后学吧,说不定有更好的模式去实现。