3-1设计模式之责任链模式(Chain-of-Responsibility)

3.1.1 模式意图:

在系统中,同一个元素可能有多个对象根据优先级对其进行逐步处理,并通过返回处理的状态判断(Ture、False、Null等)是否交由下一对象操作,一般情况下我们会使用if elseif else语句进行跳转,但是如果处理对象较多,处理优先级变动频繁,再用else语句显然不是一个优雅的行为,这时我们可以使用责任链模式来完成上述需求。

3.1.2 模式概念:

它属于行为型模式,使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

3.1.3 模式元素:

  • 请求元素(Responsibility)
  • 处理链节点抽象(Handler)
  • 处理链节点细节(ConcreteHandler1、ConcreteHandler2、ConcreteHandler3)

3.1.4 代码示例:

下面以一个吃食物请求的流程为背景,用责任链模式来展示代码示例

public class ResponsibilityContext
{
    public string Type = "肉类";
    public string Description = "我想吃**肉";
    public bool AuditResult = false;
    public string AuditRemark = "";
}
public abstract class Handler
{
    protected Handler successor;
    public void SetSuccessor(Handler successor)
    {
        this.successor = successor;
    }
    public abstract void HandleRequest(ResponsibilityContext context);
}

class ConcreteHandler1 : Handler
{
    public override void HandleRequest(ResponsibilityContext context)
    {
        context.AuditRemark += "-饮料相关-";
        if (context.Type == "饮料")
        {
            context.AuditResult = true;
            this.Log("{0}  处理请求  {1}", this.GetType().Name, context);
        }
        else if (successor != null)
        {
            successor.HandleRequest(context);
        }
    }
}

class ConcreteHandler2 : Handler
{
    public override void HandleRequest(ResponsibilityContext context)
    {
        context.AuditRemark += "-素食处理-";
        if (context.Type == "素食")
        {
            context.AuditResult = true;
            this.Log("{0}  处理请求  {1}", this.GetType().Name, context);
        }
        else if (successor != null)
        {
            successor.HandleRequest(context);
        }
    }
}

class ConcreteHandler3 : Handler
{
    public override void HandleRequest(ResponsibilityContext context)
    {
        context.AuditRemark += "-肉类处理-";
        if (context.Type == "肉类")
        {
            context.AuditResult = true;
            this.Log("{0}  处理请求  {1}", this.GetType().Name, context);
        }
        else if (successor != null)
        {
            successor.HandleRequest(context);
        }
    }
}

调用

    void Start()
    {
        ResponsibilityContext context = new ResponsibilityContext();

        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();
        Handler handler3 = new ConcreteHandler3();

        handler1.SetSuccessor(handler2);
        handler2.SetSuccessor(handler3);

        handler1.HandleRequest(context);

        this.Log($"是否处理成功{context.AuditResult}");
        this.Log($"AuditRemark:{context.AuditRemark}");
    }

3.1.5 写法对比:

3.1.6 模式分析:

责任链的主要职责就是当客户提交一个请求时,此请求沿链传递至一个ConcreteHandler对象负责处理这个请求为止。
责任链方便的地方就是可随时增加或修改ConcreteHandler。增强了给对象指派职责的灵活性。
需要注意的是,一个请求极有可能到了链的末端都不能得到处理,或者因为没有正确配置而得不到处理。

优点

  1. 请求的发送者和接收者解耦。
  2. 使得对象不需要知道链的结构。
  3. 增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。

缺点:

  1. 不能保证请求一定被处理。
  2. 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用(责任链收尾相交)。
  3. 可能不易观察运行时的特征,有碍于除错。

3.1.7 应用场景:

一个请求需要被多个对象逐步处理时。

3.1.8 小结:

责任链模式可以理解为elseif的优化版本,切记生搬硬套设计模式,适得其反。


更多设计模式详见:设计模式全家桶

发表评论