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

时间:2017-01-31 18:15:37

标签: java c# design-patterns

我很难理解Erich Gamma's本书Design Patterns关于Decorator模式的以下实施建议。

  

省略抽象的Decorator类没有必要定义一个抽象   当你只需要添加一个责任时,Decorator类。

我不明白为什么需要抽象的Decorator类?为什么所有装饰器都不能直接实现/继承IComponent / Component?

3 个答案:

答案 0 :(得分:7)

装饰器为其他一些类添加了一些功能。他将旧功能的所有消息转发到装饰类。新功能由装饰器本身处理。如果要添加的功能不止一种,那么将旧功能转发到装饰类的代码放在多个类中。这就是使用抽象装饰器的原因。

实施例: enter image description here

在上面的例子中,我们想要从IComponent层次结构中使用任何一个功能A oder功能B来解除一些类。" someFunctionality()"的转发代码。会在两个班级。所以我们提取一个抽象装饰器类(避免重复)。派生装饰器中唯一的代码现在是要添加的功能,再加上调用超类的方法。这很重要,因为如果转发的逻辑发生变化,则必须仅更改超类方法。您可以使用功能A或B修饰FirstDerived和SecondDerived。

如果你想用不超过一个功能来装饰现有的类,你就不必提取" someFunctionality"的转发,因为只有一个装饰器,这个转发代码是放在。

示例:enter image description here

Gamma的实现提示是省略抽象装饰器类,其唯一目的是转发ClassHierarchy的功能,以便在具体装饰器中只添加其新功能的重要代码

我建议你在没有抽象装饰的情况下开始。但是如果添加第二个装饰器,则必须删除重复的代码,从而在重构过程中提取抽象类。

答案 1 :(得分:3)

  

我不明白为什么需要抽象的Decorator类?为什么不能所有装饰器只是直接实现/继承IComponent / Component?

Decorator 模式中abstract类的目的是消除代码重复。 Decorator 模式的关键是允许您包装现有的组件以及新的职责。这种包装是通过创建一个 IS-A 组件和 HAS-A 组件的新类来完成的:

public class Decorator implements Component { 
    private Component component;

    public Decorator(Component component) { this.component = component; }
}

想象一下,你再引入两个装饰器。您现在必须在新的装饰器中实现类似的代码。 abstract 装饰器可以帮助您解决这个问题。通过将上面的代码移动到 abstract 类,所有具体的装饰器都可以继承它,并且无需手动重新实现装饰器骨架。

我知道上例中的Decorator没有做太多事情;但是,想象一下你想要根据某些条件禁止进一步装饰的情况。例如,如果费用超过15美元,则不允许在披萨上再添加任何配料。 abstract 装饰器可以通过在构造函数中调用组件上的 getCost 函数来处理这个问题。这将导致调用所有装饰器的所有 getCost 函数,并为您提供最终成本。如果getCost()>15,应用程序可以通知用户费用不能超过15美元。这种代码重用是 abstract 装饰器类背后的真正动机。

答案 2 :(得分:0)

我也有同样的疑问,为此我浏览了几篇文章,发现的其他几点如下:

根据“四人帮”,我们可以拥有装饰器而无需扩展抽象类,仅当我们没有太多装饰器时才放。

为什么我们应该再有抽象类

很多时候,如果我们有多个装饰器实现,可能并不需要实现所有方法,但是如果每个装饰器都实现了您的情况下的接口(IComponent),则每个装饰器都将被强制实现他们可能未实现的方法需要实现。鉴于您的界面有很多方法。