为什么我会在装饰师身上使用责任链?

时间:2009-04-14 14:38:18

标签: oop design-patterns decorator chain-of-responsibility

我只是阅读了Chain of Responsibility模式,当我更喜欢使用decorator时,我无法想象一个场景。

你怎么看? CoR是否有利基用途?

10 个答案:

答案 0 :(得分:64)

您可以在任何时候打破链条,将责任链模式与装饰器模式区分开来。装饰器可以被认为是一次执行而不与其他装饰器进行任何交互。链中的链接可以被认为是一次执行一个,因为它们各自依赖于前一个链接。

当您可以将您的程序概念化为由链接组成的链时,使用责任链模式,其中每个链接可以处理请求或将其传递给链。

当我以前使用Win32 API时,我有时需要使用它提供的挂钩功能。挂钩Windows消息大致遵循责任链模式。当您挂钩诸如WM_MOUSEMOVE之类的消息时,将调用您的回调函数。将回调函数视为链中的最后一个链接。链中的每个链接都可以决定是丢弃WM_MOUSEMOVE消息还是将链路传递到下一个链接。

如果在该示例中使用了Decorator模式,则会收到WM_MOUSEMOVE消息的通知,但是您也无法阻止其他挂钩处理它。

使用命令链模式的另一个地方是游戏引擎。同样,您可以挂钩引擎功能,事件和其他事物。对于游戏引擎,您不希望简单地添加功能。您希望添加功能并阻止游戏引擎执行其默认操作。

答案 1 :(得分:16)

这些模式之间的差异与链的何时或如何被破坏(假定链)或何时执行额外行为无关。它们的相关之处在于它们都使用组合来支持继承,以提供更灵活的解决方案。

关键区别在于装饰器添加了行为,实际上扩大了原始界面。它类似于普通扩展可以添加方法的方式,除了“子类”仅通过引用耦合,这意味着可以使用任何“超类”。

COR模式可以修改现有行为,类似于使用继承覆盖现有方法。您可以选择调用super.xxx()继续“链”或自己处理消息。

所以区别是微妙的,但装饰者的一个例子应该有所帮助:

interface Animal
{
    Poo eat(Food food);
}

class WalkingAnimal implements Animal
{
    Animal wrapped;
    WalkingAnimal(Animal wrapped)
    {
        this.wrapped = wrapped;
    }

    Position walk(Human walker)
    {
    };

    Poo eat(Food food)
    {
      return wrapped.eat(food);
    }
}

class BarkingAnimal implements Animal
{
    Animal wrapped;
    BarkingAnimal(Animal wrapped)
    {
        this.wrapped = wrapped;
    }

    Noise bark()
    {
    };

    Poo eat(Food food)
    {
        bark();
        return wrapped.eat();
    }
}

你可以看到我们可以组成一只行走的,吠叫的动物......或者实际上增加了对任何动物吠叫的能力。要直接使用这种额外的行为,我们需要保持对BarkingAnimal装饰器的引用。

所有BarkingAnimal在吃之前都会吠叫一次,这改变了现有的功能,因此类似于COR。但意图与COR不同,即找到一个会吃掉食物的动物。这里的目的是修改行为。

你可以想象一个COR应用于寻找一个将动物带走的人。这可以实现为上面的chained链接列表,也可以显示为明确的列表......或其他任何内容。

希望这是相当清楚的!

约翰

答案 2 :(得分:13)

<强>链

  

避免耦合请求的发件人   给予接收者超过   一个物体有机会处理   请求。链接接收对象   并沿着链传递请求   直到一个对象处理它。

VS

<强>装饰

  

将附加职责附加到   一个动态的对象。装饰   提供灵活的替代方案   子类化扩展   功能。

我会围绕事情发生的顺序说出来。如果你链接它们,将沿着链调用。对于装饰者,您无法保证此订单,只能附加额外的责任。

答案 3 :(得分:9)

我会说责任链装饰者的一种特殊形式。

答案 4 :(得分:8)

当您想要向对象添加功能时使用Decorator。

当许多演员中的一个可能对某个对象采取行动时使用COR。

根据类型调用特定的装饰器来执行操作; COR沿着定义的链传递对象,直到其中一个角色决定动作完成。

当有多个级别的升级到不同的处理程序时,可能会使用COR - 例如,客户对公司的价值决定调用是否达到特定支持级别的呼叫中心。

答案 5 :(得分:4)

我能想到两种情况:

  • 您没有核心对象,即在通过所有图层/过滤器后您不知道如何处理请求。 (像拦截器链这样的方面,并不关心请求结束的位置)。
  • 您需要有选择地对请求应用一些预处理或后处理。不像装饰者那样处于一般增强形式。即过滤器可能会或可能不会处理特定请求,但添加装饰器总是会增强您的对象的某些功能。

现在不能再想了,希望在这个话题中听到更多。

答案 6 :(得分:2)

<强> 装饰

  1. Decorator模式允许动态地将行为添加到单个对象。

  2. 它为子分类提供了灵活的替代方案,可用于扩展功能。即使它使用继承,它仍然从最低公分母(LCD)接口继承。

  3. 装饰器的UML图

    UML diagram for Decorator

    <强>后果:

    1. 通过装饰,还可以动态删除添加的功能。
    2. 装饰在运行时向对象添加功能,这将使调试系统功能更难。
    3. 有用的链接:

      When to Use the Decorator Pattern?

      来自维基百科的

      Decorator_pattern

      来自sourcemaking的

      decorator

      责任链

        

      责任链模式是一种由命令对象源和一系列处理对象组成的设计模式。每个处理对象都包含定义它可以处理的命令对象类型的逻辑;其余的传递给链中的下一个处理对象

      UML图

      enter image description here

      这种模式在以下情况下更有效:

      1. 多个对象可以处理命令
      2. 事先不知道处理程序
      3. 应自动确定处理程序
      4. 希望请求发送到一组对象而不明确指定其接收方
      5. 必须以动态方式指定可以处理命令的对象组
      6. 有用的链接:

        来自维基百科的

        Chain-of-responsibility_pattern

        来自oodesign的

        chain-of-responsibility-pattern

        来自sourcemaking的

        chain_of_responsibility

        真实世界示例:在公司中,指定角色对处理购买请求有特定限制。如果具有指定角色的人没有足够的权力来批准购买账单,他会将命令/请求转发给拥有更多权力的继任者。此链将继续,直到处理命令。

答案 7 :(得分:1)

我同意从结构角度来看,这两种模式非常相似。我的想法是关于最终的行为:

在处理请求的CoR元素的经典解释中打破链。

如果装饰器中的任何元素打破了链,那么它将是错误的装饰器的实现,因为基本部分的行为将会丢失。当基本行为保持不变时,装饰者的想法是透明地添加新行为。

答案 8 :(得分:0)

我认为应用这两种模式的情况是不同的。顺便说一句,对于装饰器模式,装饰器应该知道它包装的组件。而对于CoR来说,不同的拦截器可能彼此都不知道。

答案 9 :(得分:0)

在阅读“四人帮”定义后,我不相信存在真正的差异。 (为方便起见,包括在内)

  • 装饰器:允许动态包装对象以修改其现有的职责和行为
  • 责任链:通过将接收对象链接在一起,为多个对象提供处理请求的机会

维基百科将它们搞砸了一点,但其中一些有点武断。

  • Decorator通常实现为链接列表。但我认为这太低级别不能被视为模式的“部分”。
  • 责任链仅在处理数据时才处理;但确定责任和数据处理都是行为的一部分。装饰者可以轻松地做到这一点。
  • Decorator要求您致电该委托。
  • “纯”CoR链接只应在不处理数据的情况下调用该委托。

前两个属性并没有真正区分模式。第二个做,但Decorator和CoR通常实现的方式不强制执行这些属性 - 设计者只希望没有人编写打破链的装饰器或处理数据后继续链的CoRLink。

要实际实现这些属性,您需要以下内容。

强制装饰者:

abstract class Decorated {

public Decorated delegate;

public final Object doIt(Object args) {
    Object returnVal = behavior(arg);
    if(delegate != null) returnVal = delegate.doit(returnVal);
    return returnVal;
}

protected abstract Object behavior(Object args); //base or subclass behavior
}

强制执行责任链:

abstract class Link {

public Link delegate;

public final Object processIt(Obect args) {
    Object returnVal = args;
    if(isMyResponsibility) returnVal = processingBehavior(returnVal);
    else returnVal = delegate.processIt(returnVal);
    return returnVal;
}

protected abstract Boolean isMyResponsibility(Object args);

protected abstract Object processingBehavior(Object args);
}

(换句话说,你可以在javadoc上添加一行,如果你想要的就是免除责任,以防其他人搞砸你的设计 - 但为什么要把它留给机会?)