"Head First"设计模式读书笔记——装饰者模式
装饰者模式
定义:
动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。类图如下:
实例演练:
援引书中的“星巴兹咖啡”的例子。人们在购买咖啡时,可能需要加入各种调料,如巧克力,牛奶,香草等。添加不同的调料会收取不同的费用,订单系统必须考虑各种调料的处理。
《Head First设计模式》一书中给出了两个反面设计方案例子。
第一种是设计铺天盖地的类,譬如“香草咖啡”类,“牛奶咖啡”类,“香草牛奶咖啡”类等等。不用说,这肯定是最笨,最傻的设计方案。没有一个正常人会做这样的事情。
第二种是大多数初学者会想到的,就是为一个咖啡超类添加许多bool值(如Milk、Mocha、Soy、Whip等)属性用以标示是否加入了相应的调料和实现加入调料功能。如下图所示。
其他Coffe品种都继承自此Coffe超类。
现在考虑一下这种方案的可行性。就目前而言,这样的设计实现了系统所要求的功能。可一旦发生如下情况,该设计方案就显示他的不足之处:
1, 调料价格有变动。
2, 出现新的调料。
3, 对新的Coffe品种,可能有些调料不适用。
4, 顾客想加入双倍的某种调料(如牛奶)。
以上任一种情况都需要修改现有的代码,可见该方案的扩展性非常差。
第三种设计方案由本文的主角上场,用装饰者模式设计“星巴兹”咖啡店。
将装饰者模式应用到“星巴兹”咖啡店,类图如下:
相应代码实现如下。
测试系统:
编写如下代码:
{
Coffee coffee = new JavaCoffee();
coffee = new Milk(coffee);
coffee = new Whip(coffee);
coffee = new Soy(coffee);
coffee = new Mocha(coffee);
Console.WriteLine(coffee.getDescription() + "$" + coffee.cost());
}
运行结果如下:
总结:
装饰者模式为设计注入了很好的弹性,遵循了类“对扩展开放,对修改关闭”的原则。但同时也加入了大量的“小类”,初步接触时可能会感到迷惑,但只要你了解了是在和“装饰者”打交道,一切都变得合情合理了。
其实,我们经常会用到装饰者,例如JAVA中的I/O就采用了装饰者模式,援引《Head First设计模式》中的介绍,JAVA I/O类图如下:
图中InputStream为抽象组件,FileInputStream、StringBufferInputStream、ByteArrayInputStream为可以被装饰者包裹起来的具体组件,FilterInputStream就是一个抽象装饰者,而PushbackInputStream、LineNumberInputStream、DataInputStream和BufferedInputStream为具体的装饰者。刚刚学习Java的时候,经常被这些“复杂繁多”的I/O类搞昏头脑,了解了Java I/O其实就是装饰者或会发觉应用起来更加的得心应手了。