责任链模式

时间:2012-02-08 14:08:39

标签: design-patterns chain-of-responsibility

有人可以提供责任链模式的简单解释吗?我发现维基文章有点令人困惑。

6 个答案:

答案 0 :(得分:7)

一个很好的例子是java servlet filters - 在HTTP请求到达目标之前执行的代码片段。

  • 链包含多个实例,每个实例执行不同的操作
  • 链中的每个实例都可以选择传播到下一个实例,或者停止流程

因此,使用servlet过滤器,您可以拥有

  • 检查用户是否经过身份验证的过滤器。如果是,则过滤器传播到下一个过滤器

  • 下一个过滤器检查用户是否具有当前资源的权限。如果是,则传播到下一个

  • 下一个记录当前请求的URL和用户名,并始终传播到下一个

  • 链中没有其他内容,因此最终调用了目标对象

答案 1 :(得分:4)

我会在类比的帮助下尝试:

将命令视为冰球和责任处理程序类链作为单孔网络。现在想象一下这种半径不同的网络堆叠在一起(顶部有最小半径的网)。

现在你从顶部掉落冰球。如果圆盘的半径大于第一个孔,它将卡在其中并且不会下降。这意味着该命令已由第一个处理程序处理。

但是如果冰球比洞小,它将通过它进入下一个洞,依此类推,直到它被所有网捕获或掉落。冰球经过的所有网(责任处理程序类)都处理了冰球(处理命令)。

答案 2 :(得分:2)

使用此模式,您可以创建一个检查请求的对象链。 每个人依次检查请求并处理它或将其传递给链中的下一个对象

优势

  • 解耦请求的发件人及其接收者
  • 简化了对象,因为它不必知道链结构并保持对其成员的引用
  • 允许通过更改链的顺序或成员来动态添加或删除责任

缺点

  • 请求的执行没有保证,如果没有对象处理它可能会脱离链
  • 运行时特性可能难以观察和调试

潜在用例

  • 鼠标点击和键盘事件。
  • 电子邮件。例如,收到电子邮件并将其传递给第一个处理程序,即垃圾邮件处理程序。然后将其处理或传递给第二个处理程序等。

自:

Head First Design Patterns


这个模式有一个有趣的InformIT article,带有示例代码。

答案 3 :(得分:1)

该帖子受到保护,但我想给出答案,因为我认为它可能会得到改善。

责任链和过滤器。它们是一样的吗?

过滤模式靠近责任链模式。
但它远远不足以混合它们 使用相同的术语表达两个不同的概念将是一个遗憾。

在过滤器/拦截器模式中,我们没有责任的概念,因为链的多个节点可以作用于相同的流并且在模式的意图中,它是为多个处理创建的。链节点不处理请求,他们共同参与请求的处理 因此,过滤器或拦截器更像是一系列处理而不是责任链 例如,AOP用作过滤器和拦截器。我们想从一堆处理器中重复一些处理。
这不是责任问题,而是我们根据某些条件应用的多层处理问题。它对实施及其背后的逻辑产生重要影响 存储在链中的过滤器/拦截器可能具有(并且通常)它们之间没有逻辑或功能关系,而责任链的节点在它们之间始终具有逻辑或功能关系,因为它们必须处理相同的关注。 例如,在链式过滤器中,第一个过滤器可以处理日志记录问题,第二个过滤器,安全问题和最后一个编码问题...
在一系列责任中,同一个问题由链中的所有节点处理。

GOF参考 责任链意图:

通过为多个对象提供处理请求的机会,避免将请求的发送者耦合到其接收者。链接接收对象并沿链传递请求,直到对象处理它。 在责任链模式中,当链的节点处理链时,链就会停止。

现在,我将简要介绍一下它是什么以及何时使用一个简单而具体的例子。

什么是责任链?

责任链设计模式是一种行为模式。 作为所有GOF设计模式,它的名称完全适合它,因为模式定义了一个请求处理,一个对象链,转向具有停止链处理和响应请求的能力。 这种模式有利于解耦链条的组件。因此,我们可以独立更新组件并动态创建链。

何时使用责任链?

在责任链中,只有一个对象可以负责响应请求。如果我们希望不止一个候选人能够对请求采取行动,我们就会远离责任链模式。我们处在一个加工链中。过滤模式满足了这种需求。

责任链模式适用于多种情境:技术作为企业。

处理用户界面中的内部事件和用户事件是一种经常被描述的用法。 在此上下文中,链允许图形图层和组件处理用户输入,例如鼠标点击,按下键等...还有内部处理,例如图形更新处理。

责任链的示例

我们将以点击通用按钮为例来说明这一点 按钮是"泛型"因为它的行为取决于上下文。

这个想法是图形组件在从与用户操作相关的更本地组件到与用户操作相关的本地组件更少的链中排序。
一旦链的一个组件决定处理请求,就会停止链的流动。

这里有一个例子来说明这一点 想象一下" save"电子表格应用程序菜单栏中的按钮 保存包含2个电子表格的文档不应由第一个或第二个电子表格完成,因为它们不应直接耦合在它们之间。
假设,当" save"按下按钮,视图显示在第二个电子表格中。因此,链由第二个电子表格组件开始执行,因为它是与该操作相关的更本地组件。第二个电子表格组件并不认为负责处理请求,因此它们让链的更高级别组件处理它,例如:应用程序组件。当它收到请求时,应用程序组件具有处理保存请求所需的所有信息,因此它执行它 相反,如果我们在文档中只有一个电子表格,我们可以想象该动作可以由电子表格组件执行,这是自给自足的。

答案 4 :(得分:0)

理解的最佳方式是分析一个简单的例子。那就是他:

该程序将一个单词从英语翻译成其他语言(非常简化的版本:))翻译的单词被传递给后续的词典;字典形成一个链。

using System;

// The 'Handler' abstract class
abstract class Handler
{
    //chain link
    private Handler _successor;
    //
    static private Handler _first;

    public Handler Successor
    {
        set 
        {
            _successor = value;
        }
        get 
        {
            return _successor;
        }
    }
    public Handler First
    {
        set 
        {
            _first = value;
        }
        get 
        {
           return  _first;
        }
    }
    //
    public void HandleRequest(string request)
    {
        if (First == this)
        {
            Console.WriteLine("\n\tWe translate word => \"{0}\"\n", request);
            First.Translator(request);
        }
        //
        if (Successor != null)
        {
            //Translation by the successor's dictionary 
            Successor.Translator(request);

            //Transfer of word (request) to another chain (dictionary) 
            Successor.HandleRequest(request);
        }
    }
    //
    abstract public void Translator(string word);
}

//The concrete class
class GermanDictionary : Handler
{
    override public void Translator(string word)
    {
        switch (word)
        {
            case "Job":
                word = "Arbeit";
                break;
            case "Rest":
                word = "Rest";
                break;
        }
        Console.WriteLine("\t\tinto German => \"{0}\"", word);
    }
}

class FrenchDictionary : Handler
{
    override public void Translator(string word)
    {
        switch (word)
        {
            case "Job":
                word = "Travail";
                break;
            case "Rest":
                word = "Reste";
                break;
        }
        Console.WriteLine("\t\tinto French => \"{0}\"", word);
    }
}

class PolishDictionary : Handler
{
    override public void Translator(string word) 
    {
        switch (word)
        {
            case "Job":
                word = "Praca";
                break;
            case "Rest":
                word = "Odpoczynek";
                break;
        }
        Console.WriteLine("\t\tinto Polish => \"{0}\"", word);
    }
}
////
class Client
{
    static void Main()
    {
        Handler h1 = new FrenchDictionary();
        Handler h2 = new GermanDictionary();
        Handler h3 = new PolishDictionary();

        //Determining the consequences in the chain
        h1.First=h1;
        h1.Successor=h2;
        h2.Successor=h3;
        h3.Successor=null;

        //The word that is translated
        string request = "Job";

        //Starting the recursive method.
        h1.HandleRequest(request) ;

        //Another word is translated.
        request = "Rest";
        h1.HandleRequest(request);

        Console.ReadKey();
    }
}

/*output:

 We translate word => "Job"

    into French => "Travail"
    into German => "Arbeit"
    into Polish => "Praca"

 We translate word => "Rest"

    into French => "Reste"
    into German => "Rest"
    into Polish => "Odpoczynek"
 */

答案 5 :(得分:0)

您可以在Chain of responsibility - lambda function implementation中找到带有lambda函数的责任链模式的示例实现。

它涵盖了通过不同的参与者(经理,导演,总裁,推销员)处理购买请求的功能。