责任链模式

7

有人能够提供一份责任链模式的简单解释吗?我发现维基百科上的文章有点令人困惑。

6个回答

15
一个非常好的例子是Java Servlet Filters - 这些代码片段在HTTP请求到达目标之前执行。
  • 链中包含多个实例,每个实例执行不同的操作
  • 链中的每个实例都可以选择传播到下一个实例或停止流程
因此,使用Servlet过滤器,您可以有:
  • 检查用户是否已通过身份验证的过滤器。如果是,则过滤器会传播到下一个过滤器

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

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

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


那么前面的信息是否有效地传递到下一个呢?也就是说,filter firstFilter + 3 是否包含了 firstFilter 1 和 2 的信息? - Dollarslice
2
是的,您可以通过“chain”传递任何内容。在过滤器的情况下,您会传递请求和响应:chain.doFilter(request, response)。 - Bozho

4
使用这种模式,您可以创建一个对象链来检查请求。每个对象依次检查请求并处理它或将其传递给链中的下一个对象。
优点: - 解耦请求发送者和接收者 - 简化了对象,因为它不必知道链结构并保留对其成员的引用 - 允许通过更改链的顺序或成员来动态添加或删除责任
缺点: - 不能保证请求的执行,如果没有对象处理它,则可能掉落链 - 运行时特性可能难以观察和调试
潜在用例: - 鼠标点击和键盘事件。 - 电子邮件。例如,电子邮件被接收并传递给第一个处理程序,垃圾邮件处理程序。然后它要么被处理,要么被传递给第二个处理程序等等。
来自:

Head First Design Patterns


这里有一篇有趣的InformIT文章,其中包含样例代码。

为什么解耦发送者和接收者是有益的? - Dollarslice
1
@SirYakalot:对于接收者未被发送者知晓的情况,或者您希望根据其他标准动态指定接收者的情况下使用。 - JRL
您会在工作流程中使用COR吗?其中工作流程中的每个步骤都是一条链中的命令(或者是该链中的子链)吗? - jamiebarrow

4

我将通过一个类比来解释:

把被处理的命令想象成一枚曲棍球,而责任链处理程序类就像是只有一个孔的网。现在想象一下,这些孔的半径不同的网被叠放在一起(最小半径的网在上面)。

现在你从上面扔下曲棍球。如果曲棍球的半径大于第一个孔的半径,它就会被卡住,不会掉落到更低的位置。这意味着第一个处理程序已经处理了该命令。

但如果曲棍球的半径小于孔的半径,它将穿过孔,进入下一个孔,以此类推,直到被卡住或掉落到所有的网中。所有曲棍球穿过的网(责任链处理程序类)都已经处理了该曲棍球(处理了该命令)。


3
这篇文章受到保护,但我想给出一个答案,因为我认为它可能可以改进。
责任链模式和过滤器模式。它们是一样的吗?
过滤器模式与责任链模式非常相似。 但它足够不同,以至于不能混淆两者。 使用相同的术语来表达两个不同的概念是可惜的。
在过滤器/拦截器模式中,我们没有责任的概念,因为链的多个节点可以对同一流程进行操作,并且在该模式的意图中,它被创建用于多个处理。链的节点不处理请求,而是共同参与处理请求。 因此,过滤器或拦截器更像是处理的链而不是责任链。 例如,面向方面的编程(AOP)就像过滤器和拦截器一样工作。我们希望从处理器堆栈中重复一些处理。这不是一个责任的问题,而是一个我们根据某些条件或不应用的多层处理问题。这对实现和其背后的逻辑有重要的影响。 存储在链中的过滤器/拦截器可能(并经常)彼此之间没有逻辑或功能关系,而责任链的节点始终具有逻辑或功能关系,因为它们必须处理相同的问题。 例如,在链过滤器中,第一个过滤器可能处理日志记录问题,第二个过滤器可能处理安全问题,最后一个过滤器可能处理编码问题...... 在责任链中,所有节点都处理相同的问题。
GOF参考:责任链模式意图:
通过为请求给多个对象处理请求的机会,避免将请求的发送者与接收者耦合。链接接收对象并沿着链传递请求,直到对象处理它。 在责任链模式中,当链的节点处理它时,链就停止了。
现在,我将简要描述什么是责任链以及在何时使用它,同时提供一个简单而具体的示例。
什么是责任链?
责任链设计模式是一种行为模式。 像所有GOF设计模式一样,它的名称非常适合,因为该模式定义了一个对象链来处理请求,这些对象依次具有停止链处理并响应请求的能力。 此模式的优点在于解耦链的组件。因此,我们可以独立更新组件并动态创建链。
何时使用责任链?
在责任链中,只有一个对象可以负责响应请求。如果我们希望有多个候选人能够对请求进行操作,则需要远离责任链模式。我们处于处理链中。过滤器模式解决了这种需求。
责任链模式适用于多个上下文:技术和业务。
处理用户界面中的内部和用户事件是一个经常描述的用法。在这种情况下,链允许图形层和组件处理用户输入,例如鼠标单击、按下键等,同时也可以处理内部处理,例如图形更新处理。 使用责任链模式的示例 我们将以通用按钮上的单击为例来说明这一点。 该按钮是“通用”的,因为其行为取决于上下文。
图形组件按照与用户操作相关的最局部组件到最不局部的组件的顺序排序成链。 只要链的一个组件决定处理请求,链的流程就会停止。
以下是一个示例来说明这一点。 假设电子表格应用程序的菜单栏中有一个“保存”按钮,其中包含2个电子表格。保存文档不应由第一个或第二个电子表格执行,因为它们不应直接耦合在一起。 假设单击“保存”按钮时,视图显示在第二个电子表格上。因此,链通过从第二个电子表格组件开始执行来执行。第二个电子表格组件认为不负责处理请求,因此他们让链的更高级别组件处理它,例如:应用程序组件。当它收到请求时,应用程序组件具有处理保存请求所需的所有信息,因此它执行它。 相反,在只有一个电子表格的情况下,我们可以想象该操作可能由自给自足的电子表格组件执行。

2

理解编程最好的方法是分析一个简单的例子。这就是它:

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

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

0

您可以在此处找到使用Lambda函数实现责任链模式的示例实现责任链 - Lambda函数实现

它涵盖了通过不同角色(经理、董事、总裁、销售员)处理采购请求的功能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接