总目录
前言
职责链,就是一条处理请求的职责链条,生活中常见的就是 请假申请,例如你家里有事情,提交了请假申请,然后公司规定:
当 请假天数 <=
3天,由项目主管审批,
当 3天 <
请假天数 <=
10天,由经理审批,
当 请假天数 >
10天,由CEO审批。
这就是一条职责链。
1 基础介绍
- 定义:某个请求需要多个对象进行处理,从而避免请求的发送者和接收之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
- "责任链"顾名思义,是指一个需要负责处理请求的链条。每个链条节点都是一个单独的责任者,由责任者自己决定是否处理请求或交给下一个节点。
- 职责链模式中的角色:
- 抽象处理者角色(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#中责任链模式详解