C# 设计模式之职责链模式

总目录


前言

职责链,就是一条处理请求的职责链条,生活中常见的就是 请假申请,例如你家里有事情,提交了请假申请,然后公司规定:

当 请假天数 <= 3天,由项目主管审批,

当 3天 < 请假天数 <= 10天,由经理审批,

当 请假天数 > 10天,由CEO审批。

这就是一条职责链。


1 基础介绍

  1. 定义:某个请求需要多个对象进行处理,从而避免请求的发送者和接收之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
  2. "责任链"顾名思义,是指一个需要负责处理请求的链条。每个链条节点都是一个单独的责任者,由责任者自己决定是否处理请求或交给下一个节点。
  3. 职责链模式中的角色:
    • 抽象处理者角色(Handler):抽象处理者定义了一个处理请求的接口,它一般设计为抽象类,由于不同的具体处理者处理请求的方式不同,因此在其中定义了抽象请求处理方法。因为每一个处理者的下家还是一个处理者,因此在抽象处理者中定义了一个自类型的对象,作为其对下家的引用。通过该引用,处理者可以连成一条链。
    • 具体处理者角色(ConcreteHandler):具体处理者是抽象处理者的子类,它可以处理用户请求,在具体处理者类中实现了抽象处理者中定义的抽象处理方法,在处理请求之前需要进行判断,看是否有相应的处理权限,如果可以处理请求就处理它,否则将请求转发给后继者;在具体处理者中可以访问链中下一个对象,以便请求的转发。

2 使用场景

  • 一个系统的审批需要多个对象才能完成处理的情况下,例如请假系统等。
  • 代码中存在多个if-else语句的情况下,此时可以考虑使用责任链模式来对代码进行重构
  • 有多个对象可以处理同一个请求,具体哪个对象处理该请求有运行时刻自动确定。客户端只需将请求提交到链上,无须关心请求的处理对象是谁以及它是如何处理的。
  • 不明确指定接受者的情况下,向多个对象中的一个提交一个请求。请求的发送者与请求者解耦,请求将沿着链进行传递,寻求响应的处理者。
  • 可动态指定一组对象处理请求。客户端可以动态创建职责链来处理请求,还可以动态改变链中处理者之间的先后次序

3 实现方式

我们以公司内请假为例:

当 请假天数 <= 3天,由项目主管审批,

当 3天 < 请假天数 <= 10天,由经理审批,

当 请假天数 > 10天,由CEO审批。

1. 传统实现方式

csharp 复制代码
    public class LeaveRequest
    {
        //请假人姓名
        public string Name { get; set; }
        //请假天数
        public int Num { get; set; }
        //请假事由
        public string Reason { get; set; }

        public LeaveRequest(string name,int num,string reason)
        {
            Name= name;
            Num= num;
            Reason= reason;
        }
    }


    public abstract class Handler
    {

        public abstract void HandleRequest();
    }

    public class ProjectLeader : Handler
    {
        public override void HandleRequest()
        {
            Console.WriteLine("ProjectLeader:审批通过");
        }
    }

    public class Manager : Handler
    {
        public override void HandleRequest()
        {
            Console.WriteLine("Manager:审批通过");
        }
    }

    public class CEO : Handler
    {
        public override void HandleRequest()
        {
            Console.WriteLine("CEO:审批通过");        }
    }

客户端调用:

csharp 复制代码
        static void Main(string[] args)
        {
            LeaveRequest leaveRequest = new LeaveRequest("张三",12,"事假");
            ProjectLeader projectLeader = new ProjectLeader();
            Manager manager = new Manager();
            CEO  cEO = new CEO();
            if (leaveRequest.Num <= 3)
            {
                projectLeader.HandleRequest();
            }
            else if (leaveRequest.Num > 3 && leaveRequest.Num <= 10)
            {
                manager.HandleRequest();
            }
            else
            {
                cEO.HandleRequest();
            }

            Console.ReadKey();
        }

如果我们请假的规则发生变化,例如我们新增一个10-15天的请假审批,我们需要再新增一个else if 的判断,这样是违背开闭原则的,因此我们改进一下代码。

2. 职责链模式实现方式

csharp 复制代码
	//请假申请
    public class LeaveRequest
    {
        //请假人姓名
        public string Name { get; set; }
        //请假天数
        public int Num { get; set; }
        //请假事由
        public string Reason { get; set; }

        public LeaveRequest(string name,int num,string reason)
        {
            Name= name;
            Num= num;
            Reason= reason;
        }
    }

    public abstract class Handler
    {
        // 下一个处理人,也就是下一位审批人
        public Handler NextHandler { get; set; }
        //审批人姓名
        public string Name { get; set; }
        public Handler(string name)
        {
            this.Name = name;
        }

        public abstract void HandleRequest(LeaveRequest leaveRequest);
    }

    public class ProjectLeader : Handler
    {
        public ProjectLeader(string name) : base(name)
        {
        }

        public override void HandleRequest(LeaveRequest leaveRequest)
        {
            if (leaveRequest.Num<=3)
            {
                Console.WriteLine($"项目主管:{this.Name} 审批了{leaveRequest.Name} {leaveRequest.Num}天的请假申请");
                return;
            }
            this.NextHandler?.HandleRequest(leaveRequest);
        }
    }

    public class Manager : Handler
    {
        public Manager(string name) : base(name)
        {
        }

        public override void HandleRequest(LeaveRequest leaveRequest)
        {
            if (leaveRequest.Num>3&&leaveRequest.Num <= 10)
            {
                Console.WriteLine($"经理:{this.Name} 审批了{leaveRequest.Name} {leaveRequest.Num}天的请假申请");
                return;
            }
            this.NextHandler?.HandleRequest(leaveRequest);
        }
    }

    public class CEO : Handler
    {
        public CEO(string name) : base(name)
        {
        }

        public override void HandleRequest(LeaveRequest leaveRequest)
        {
            Console.WriteLine($"CEO:{this.Name} 审批了{leaveRequest.Name} {leaveRequest.Num}天的请假申请");
        }
    }

客户端调用:

csharp 复制代码
        static void Main(string[] args)
        {

            LeaveRequest leaveRequest = new LeaveRequest("张三",12,"事假");

            Handler projectLeader = new ProjectLeader("李四");
            Handler manager = new Manager("王二");
            Handler cEO = new CEO("赵六");
            projectLeader.NextHandler = manager;
            manager.NextHandler= cEO;

            projectLeader.HandleRequest(leaveRequest);

            Console.ReadKey();
        }

在这个代码示例中,我们定义了一个抽象处理者 Handler,并在其中定义了一个对下一个处理者的引用 NextHandler。然后,定义了三个具体处理者 ProjectLeader,Manager 和 CEO,并实现了 Handler 接口中的 HandleRequest 方法。在 HandleRequest 方法中,每个具体处理者对象都会根据自己的能力判断是否能够处理该请求,如果能够处理,则直接处理;否则将请求转发给下一个处理者对象。

4 优缺点分析

  • 优点:

    • 降低耦合度:降低了请求发送者和接收者之间的耦合。

    • 职责更清晰:把多个条件判定分散到各个处理类中,使得代码更加清晰,责任更加明确。

  • 缺点:

    • 在找到正确的处理对象之前,所有的条件判定都要执行一遍,当责任链过长时,可能会引起性能的问题。
    • 可能导致某个请求不被处理。
    • 客户端需要组装这个链条,耦合了客户端和链条的组成结构,可以把这个在客户端的组合动作提到外面,通过配置来做,会更好点。

结语

希望以上内容可以帮助到大家,如文中有不对之处,还请批评指正。


参考资料:
C#设计模式17------责任链模式的写法
C#设计模式系列:职责链模式(Chain of Responsibility)
C#设计模式(21)------责任链模式
C#设计模式之二十职责链模式(Chain of Responsibility Pattern)【行为型】
c#中责任链模式详解

相关推荐
2501_9061505614 分钟前
私有部署问卷系统操作实战记录-DWSurvey
java·运维·服务器·spring·开源
better_liang26 分钟前
每日Java面试场景题知识点之-TCP/IP协议栈与Socket编程
java·tcp/ip·计算机网络·网络编程·socket·面试题
niucloud-admin38 分钟前
java服务端——controller控制器
java·开发语言
To Be Clean Coder39 分钟前
【Spring源码】通过 Bean 工厂获取 Bean 的过程
java·后端·spring
Fortunate Chen1 小时前
类与对象(下)
java·javascript·jvm
程序员水自流1 小时前
【AI大模型第9集】Function Calling,让AI大模型连接外部世界
java·人工智能·llm
‿hhh1 小时前
综合交通运行协调与应急指挥平台项目说明
java·ajax·npm·json·需求分析·个人开发·规格说明书
小徐Chao努力1 小时前
【Langchain4j-Java AI开发】06-工具与函数调用
java·人工智能·python
无心水1 小时前
【神经风格迁移:全链路压测】33、全链路监控与性能优化最佳实践:Java+Python+AI系统稳定性保障的终极武器
java·python·性能优化
萧曵 丶1 小时前
Synchronized 详解及 JDK 版本优化
java·多线程·synchronized