装饰者模式的GoF解释令人困惑(或者只是完全错误)

时间:2010-10-14 04:02:51

标签: design-patterns

我正在讨论一些设计模式问题,我查看了GoF中Decorator模式的定义和示例。它说

  

动态地将附加职责附加到对象。装饰器为子类化提供了灵活的替代方法,以扩展功能。

它给出了使用继承的装饰器的例子,但绝对不是动态的。

NetObjectives犯了同样的错误:

http://www.netobjectives.com/PatternRepository/index.php?title=TheDecoratorPattern

关于装饰器的波特兰图案库讨论表明存在关于什么是装饰者和不是装饰者的混淆

http://c2.com/cgi/wiki?DecoratorPattern

Wikipedia通过注意装饰器内的委托应该在构造时设置(其他DI技术也可以工作)来理解这种矛盾。

http://en.wikipedia.org/wiki/Decorator_pattern

Decorator模式的所有示例(在Java或C ++中)都需要通过继承或通过实现接口来构建静态构造。然而,GoF中的解释说,附加职责是动态附加的。但这完全是错误的。

PPR上的评论讨论了可以在运行时添加方法的动态语言,但Java和C ++不是动态的,而Decorator的解释并不仅限于Groovy和Lisp等动态语言。

对装饰器的正确解释是不是说在不支持动态方法创建的语言中涉及静态和动态构造?

GoF的解释是错误的,如他们自己的例子所示,或者我误解了什么?

2 个答案:

答案 0 :(得分:6)

<强>动态 我认为“动态”这个词的含义与GOF写这本书的时候有所不同。 我猜他们打算说的是“在没有实际修改底层对象的代码/定义的情况下向对象添加前/后行为。”对于客户,对象(装饰与否)看起来是相同的。 今天,dynamic与动态语言相关联,从这个意义上说,意味着松散的类型以及在运行时向对象添加方法/行为的能力。

替代子类化

  

装饰者模式是一个   子类化的替代方案。   子类化在编译时添加行为   时间,而变化会影响所有人   原始类的实例;   装饰可以提供新的行为   单个对象的运行时。

     

这种差异变得最重要   什么时候有几个独立的   扩展功能的方法。在   一些面向对象的编程   语言,类无法创建   在运行时,通常不是   可以预测,在设计时,   扩展的组合将是什么   被需要。这意味着一个新的   每个人都必须上课   可能的组合。相比之下,   装饰器是对象,创建于   运行时,可以组合在一起   每次使用的基础。    - 维基百科

装饰器使用继承,但是它们不从它们正在装饰的对象继承。它们继承公共接口,以便公开与装饰对象相同的方法(模仿)。他们使用组合行为 - 通过委托添加事后行为。

var dao = new PerformanceTrackingDecorator(new TurboSpeedDecorator(SqlDataAccessObject))
// use dao and later..
dao = new PerformanceTrackingDecorator(new TurboSpeedDecorator(XmlDataAccessObject))
//at runtime, I've added certain behavior to Sql and Xml DAOs

答案 1 :(得分:0)

GoF的解释看起来很糟糕。当他们的例子是子类时,调用Decorator作为子类化的替代方法是非常令人困惑的。

GoF说装饰对象及其装饰器必须具有一致的接口。显然这是模式的要求,他们用继承来证明这一点。所以它们的Decorator模式都有动态和静态组件。

我还可以看到你如何反转模式并使装饰器成为装饰对象的委托,但这可能会导致复杂的实现。

在像Lisp或Groovy这样的动态语言中,我认为你可以将装饰逻辑合并到类本身的draw()逻辑中。接口一致性的要求不是必需的,也不需要为装饰对象和装饰器分别设置类。

我要将学习Lisp添加到我的Bucket List中,这样我就可以看到设计模式如何在动态语言中发生变化。