【问题标题】:Calling non-decorated methods on decorator object在装饰器对象上调用非装饰方法
【发布时间】:2017-03-24 16:59:52
【问题描述】:

假设我们已经实现了如下图所示的装饰器模式。使用 CondimentDecorator 类,可以装饰 Beverage 类。 cost()getDescription() 方法会处理这个问题。

当创建如下所示的装饰饮料 时,调用方法getName() 对装饰对象不起作用。为了完成这项工作,这个方法也应该放在类 CondimentDecorator 中,并将调用委托给组合的 beverage 变量。

Beverage b = new Milk(new Espresso("A very nice espresso"));
b.getName() // returns null

当有很多不需要装饰的方法时,所有这些也应该放在CondimentDecorator中,以简单地委托。所以问题是:解决这个“问题”的简洁(普遍接受的)方法是什么?

【问题讨论】:

  • 将它们添加到CondimentDecorator 假设它是装饰器基类的确切问题是什么(实现的方法,即 operation1() 等。仅存在于一个类中)
  • “问题”是所有这些方法(例如 operation1())也应该放在 CondimentDecorator 中以简单地委托,并且当有许多这样的方法时,它会“污染”我认为的装饰类
  • 如果operation1()没有装饰任何东西,为什么你需要把它放在CondimentDecorator里面?
  • 因为,假设operation1()Beverage 类返回一个名为name 的属性,在未将其委托给组合的beverage 对象的情况下对装饰对象调用此方法不起作用。
  • 根据图表,CondimentDecoratorBeverage 的子类,因此调用方法getName()作用于装饰对象。

标签: java design-patterns decorator


【解决方案1】:

在 Java 或 C# 等静态类型 语言(是的,C# 不是完全静态类型的,我知道 DLR 和动态)中普遍接受的解决此“问题”的方法是装饰方法显式委托给装饰对象。该解决方案具有简单明确的明显优势。

在您的示例中,如果您不覆盖 getName,则表示您想要更改被装饰对象的行为,这正是装饰器模式的目的。

如果您默认选择委托给装饰对象,那么它看起来好像继承被破坏了,因为 CondimentDecorator 继承自 Beverage 但不使用基类的方法。

然后,要改变这种行为,您需要以某种方式定义不委托给装饰对象的方法,但应该“像往常一样继承”。 这不会很明显而且很混乱。

话虽如此,您想要实现的目标应该可以在 Java 中实现。

例如在 .NET 中,您可以通过以下方式做到这一点,我相信 Java 也有类似的东西

  1. 通过生成使用继承来动态修改对象行为的动态运行时代理,请参阅Castle Dynamic Proxy
  2. 通过使用 MSIL 重写技术,在编译时重写您的中间代码来修改它,例如参见 Fody - Method decorator

此外,请查看prototypical inheritance works in JavaScript - 该行为与您尝试实现的行为非常相似

【讨论】:

    【解决方案2】:

    在您的情况下,如果只有少量 operation1(),则可以向 CondimentDecorator 添加委托调用。如果只有少数 call() 需要装饰,则可以在需要时制作装饰器,例如: DecoratorFactory.make(new Milk(new Espresso("A very nice espresso"))).getDescription();

    CondimentDecorator.getDescription(new Milk(new Espresso("A very nice espresso")));

    关键:模式为您服务。

    【讨论】:

      猜你喜欢
      • 2020-01-11
      • 2014-01-14
      • 1970-01-01
      • 2013-10-20
      • 2019-11-18
      • 2018-05-07
      • 1970-01-01
      • 2019-12-20
      • 2017-05-25
      相关资源
      最近更新 更多