【问题标题】:The Chain of Responsibility Pattern责任链模式
【发布时间】:2012-02-08 14:08:38
【问题描述】:

有人可以简单解释一下责任链模式吗?我发现 wiki 文章有点混乱。

【问题讨论】:

    标签: design-patterns chain-of-responsibility


    【解决方案1】:

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

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

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

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

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

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

    • 链中没有其他东西,所以最终调用了目标对象

    【讨论】:

    • 那么之前的信息是否有效地延续到了下一个?如,过滤器 firstFilter + 3 是否包含 firstFilters 1 和 2 的信息?
    • 是的,你可以通过“链”传递任何东西。在过滤器的情况下,您传递请求和响应:chain.doFilter(request, response)
    【解决方案2】:

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

    把被处理的命令想象成一个冰球,把责任链处理程序类想象成带有单孔的网。现在想象一下这种不同半径的网堆叠在一起(顶部有最小半径孔的网)。

    现在你从顶部放下冰球。如果冰球的半径大于第一个洞,它会卡在里面,不会掉到更低的地方。表示该命令已由第一个处理程序处理。

    但是如果冰球比洞小,它会穿过它到达下一个洞,依此类推,直到它被抓住或穿过所有的网。冰球经过的所有网络(责任处理程序类)都处理了冰球(处理了命令)。

    【讨论】:

      【解决方案3】:

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

      好处

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

      缺点

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

      潜在用例

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

      发件人:


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

      【讨论】:

      • 为什么解耦发送者和接收者有好处?
      • @SirYakalot:适用于发送者尚不知道接收者的情况,或者您希望根据其他条件动态指定接收者。
      • 您是否会将 COR 用于工作流,其中工作流中的每个步骤都是某个链(或链中的子链)中的命令?
      【解决方案4】:

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

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

      过滤器模式离责任链模式很近。
      但不混合它们就足够了。
      用同一个词来表达两个不同的概念会很可惜。

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

      GOF 参考 责任链意图:

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


      现在,我将通过一个简单而具体的例子简要描述它是什么以及何时使用它。

      责任链是什么?

      责任链设计模式是一种行为模式。 与所有 GOF 设计模式一样,它的名称非常适合它,因为该模式定义了要处理的请求,一个对象链,轮流具有停止链处理并响应请求的能力。 这种模式提供了解耦链组件的优势。因此,我们可以独立更新组件并动态创建链。

      何时使用责任链?

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

      责任链模式适用于多种情况:技术即业务。

      在用户界面中处理内部和用户事件是一种经常被描述的用法。 在这种情况下,该链允许图形层和组件处理用户输入,例如鼠标单击、按下的键等……而且还允许内部处理,例如图形更新处理。

      责任链示例

      我们将以单击通用按钮的例子来说明这一点。
      该按钮是“通用的”,因为它的行为取决于上下文。

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

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

      【讨论】:

        【解决方案5】:

        最好的理解方法是分析一个简单的例子。就是他:

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

        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"
         */
        

        【讨论】:

          【解决方案6】:

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

          它涵盖了通过不同参与者(经理、总监、总裁、销售员)处理采购请求的功能。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-09-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-04-12
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多