装饰器模式:为什么我们需要一个抽象的装饰器?

2022-09-01 04:21:22

这个问题已经在这里提出来了,但不是回答具体问题,而是给出了装饰器图案如何工作的描述。我想再问一次,因为仅仅通过阅读装饰器模式的工作原理,答案对我来说并不明显(我已经阅读了维基百科文章和“Head First Design Patterns”一书中的部分)。

基本上,我想知道为什么必须创建一个抽象装饰器类来实现(或扩展)某些接口(或抽象类)。为什么所有新的“装饰类”都不能简单地实现(或扩展)基本抽象对象本身(而不是扩展抽象装饰器类)?

为了使这一点更加具体,我将使用处理咖啡饮料的设计模式书中的示例:

  • 有一个抽象组件类,称为Beverage
  • 简单的饮料类型,如简单地扩展HouseBlendBeverage
  • 为了装饰饮料,创建了一个抽象类,该类扩展并具有CondimentDecoratorBeverageBeverage
  • 假设我们想添加一个“牛奶”调味品,创建了一个类,该类扩展了MilkCondimentDecorator

我想理解为什么我们需要这个类,为什么这个类不能简单地扩展类本身,并在它的构造函数中传递一个实例。CondimentDecoratorMilkBeverageBeverage

希望这很清楚...如果不是我只是想知道为什么抽象装饰器类对于这个模式是必要的?谢谢。

编辑:我试图实现这个,省略了抽象装饰器类,它似乎仍然有效。此抽象类是否存在于此模式的所有描述中,仅仅是因为它为所有新的修饰类提供了标准接口?


答案 1

晚一年半总比没有好:

不需要某个接口的修饰器的基类。

但是,拥有:

  • 首先,作为记录从它派生的类是所讨论的接口的装饰器的一种手段

  • 但大多数情况下,因为装饰器通常不需要向装饰界面的每个方法添加功能。

因此,基装饰器类允许派生装饰器仅实现它们实际需要向其添加某些功能的接口方法,而将其余方法留给基类以提供默认实现。(它只是将调用委托给 decoree。

与此相反,编写从头开始实现修饰接口的修饰器,编译器要求您为接口的每个方法提供实现,无论您的修饰器是否会向其添加任何功能。

就是这么简单,真的。


答案 2

我想知道同样的事情。回到源代码,GOF设计模式,我在装饰器章节的“实现”下看到了这一点:

“省略抽象装饰器类。当您只需要添加一个职责时,无需定义抽象的 Decorator 类。当您处理现有的类层次结构而不是设计新的类层次结构时,通常就是这种情况。在这种情况下,您可以将 Decorator 将组件请求转发到混凝土装饰器中的责任合并。

因此,至少在这种情况下,似乎GOF同意您的看法:-)

我不确定“一个责任”的含义是什么。我不确定“一个以上的责任”是否意味着一个混凝土装饰师有多个责任或多个混凝土装饰师,每个混凝土装饰师都有一个责任。无论哪种方式,我都不明白为什么抽象装饰器是必要的。我的猜测是,tvanfosson的答案(在他自己答案的评论中)是正确的 - 一旦你开始创建一些装饰类,它就澄清了将它们分组到超类下的设计决策。另一方面,如果只有一个类,如果你添加第二个类,它只是在基本组件和装饰器之间作为一个毫无意义的中间人,它可能会使设计决策不那么清晰(话虽如此,你很可能会在某个时候想要添加更多,所以即使在单一情况下,也许最好包括抽象装饰器......

无论如何,这似乎与使设计清晰有关,而不是代码工作与无效之间的区别。