"Head First"设计模式读书笔记——装饰者模式

装饰者模式

定义

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


实例演练:

援引书中的“星巴兹咖啡”的例子。人们在购买咖啡时,可能需要加入各种调料,如巧克力,牛奶,香草等。添加不同的调料会收取不同的费用,订单系统必须考虑各种调料的处理。

Head First设计模式》一书中给出了两个反面设计方案例子。

第一种是设计铺天盖地的类,譬如“香草咖啡”类,“牛奶咖啡”类,“香草牛奶咖啡”类等等。不用说,这肯定是最笨,最傻的设计方案。没有一个正常人会做这样的事情。

第二种是大多数初学者会想到的,就是为一个咖啡超类添加许多bool值(如MilkMochaSoyWhip等)属性用以标示是否加入了相应的调料和实现加入调料功能。如下图所示。


其他Coffe品种都继承自此Coffe超类。

现在考虑一下这种方案的可行性。就目前而言,这样的设计实现了系统所要求的功能。可一旦发生如下情况,该设计方案就显示他的不足之处:

1, 调料价格有变动。

2, 出现新的调料。

3, 对新的Coffe品种,可能有些调料不适用。

4, 顾客想加入双倍的某种调料(如牛奶)。

以上任一种情况都需要修改现有的代码,可见该方案的扩展性非常差。

第三种设计方案由本文的主角上场,用装饰者模式设计“星巴兹”咖啡店。

将装饰者模式应用到“星巴兹”咖啡店,类图如下:


相应代码实现如下。

Decorator

测试系统:

编写如下代码:

static void Main(string[] args)
        
{
            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为抽象组件,FileInputStreamStringBufferInputStreamByteArrayInputStream为可以被装饰者包裹起来的具体组件,FilterInputStream就是一个抽象装饰者,而PushbackInputStreamLineNumberInputStreamDataInputStreamBufferedInputStream为具体的装饰者。刚刚学习Java的时候,经常被这些“复杂繁多”的I/O类搞昏头脑,了解了Java I/O其实就是装饰者或会发觉应用起来更加的得心应手了。


posted @ 2008-03-28 17:19  Neeo  阅读(1821)  评论(5编辑  收藏  举报