代码之家  ›  专栏  ›  技术社区  ›  Dean Schulze

GOF对装饰图案的解释令人困惑(或者只是明显的错误)

  •  4
  • Dean Schulze  · 技术社区  · 14 年前

    我将讨论一些设计模式问题,并查看了GOF中装饰模式的定义和示例。它说

    动态地将附加责任附加到对象上。修饰符为扩展功能提供了灵活的子类化替代方案。

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

    NetObjects犯同样的错误:

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

    波特兰模式存储库对decorator的讨论表明,对于什么是decorator和什么不是decorator存在混淆。

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

    维基百科通过指出装饰器内部的代表应该在构建时设置(其他DI技术也会起作用),来理解这一矛盾。

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

    装饰器模式(Java或C++)的所有示例都需要通过继承或实现接口来实现静态结构。然而,GOF的解释是,额外的责任是动态附加的。但这完全是错误的。

    PPR中的注释讨论了在运行时可以添加方法的动态语言,但是Java和C++不是动态的,而装饰器的解释并不是说它仅限于像Groovy和Lisp这样的动态语言。

    对decorator的正确解释是否会说,在不支持动态方法创建的语言中,静态和动态构造都涉及到了?

    戈夫的解释完全是错误的,正如他们自己的例子所示,或者我误解了什么?

    2 回复  |  直到 14 年前
        1
  •  6
  •   Gishu    14 年前

    动态的 我认为“动态”这个词的含义与共和党写这本书时有所不同。 我猜他们想说的是“在不实际修改基础对象的代码/定义的情况下向对象添加前/后行为”。对于客户机,对象(修饰或不修饰)似乎是相同的。 今天,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
    
        2
  •  0
  •   Dean Schulze    14 年前

    看来戈夫的解释写得很糟糕。当实例是子类时,调用decorator作为子类的替代方法是非常令人困惑的。

    Gof说,被装饰的对象及其装饰者必须有一致的接口。显然,这是模式的一个要求,它们通过继承来证明这一点。因此,它们的装饰器模式中既有动态组件,也有静态组件。

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

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

    我将把学习lisp添加到bucket列表中,以便了解动态语言中设计模式的变化。