责任链模式
一、定义
多个对象都有机会处理某个请求,将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
二、UML类图
-
Handler:抽象处理者角色,是一个处理请求的接口或抽象类;
-
ConcreteHandler:具体的处理者角色,具体的处理者接收到请求后可以选择将请求处理掉,或者将请求传递给下一个处理者。
-
ConcreteStrategy:具体的策略实现。
三、示例
用程序实现一个请假流程,根据请假天数不同,需要各级领导审批,例如,如果请假时长不超过1天,则直接团队负责人申请即可,超过1天不超过3天则需要项目经理审批通过才行,而超过3天不超过7天则需要CTO审批等等。
代码
1.Manager.cs
public abstract class Manager { public Manager NextManager { get; set; } public string Name { get; set; } public Manager(string name) { Name = name; } public void HandleRequest(LeaveContext context) { if (CanHandle(context)) { Handle(context); return; } NextManager?.HandleRequest(context); } protected abstract bool CanHandle(LeaveContext context); protected abstract void Handle(LeaveContext context); }
2.TL.cs
/// <summary> /// 团队领导者 /// </summary> public class TL : Manager { public TL(string name): base(name) { } protected override bool CanHandle(LeaveContext context) { return context.Request.LeaveDays <= 1; } protected override void Handle(LeaveContext context) { context.Response = new LeaveResponse { Approver = "TL:" + Name, IsAgreed = true }; } }
3.PM.cs
/// <summary> /// 项目经理 /// </summary> public class PM : Manager { public PM(string name): base(name) { } protected override bool CanHandle(LeaveContext context) { return context.Request.LeaveDays > 1 && context.Request.LeaveDays <= 3; } protected override void Handle(LeaveContext context) { context.Response = new LeaveResponse { Approver = "PM:" + Name, IsAgreed = true }; } }
4.HR.cs
public class HR { private List<Manager> _managers = new List<Manager>(); public void AddManager(Manager manager) { _managers.Add(manager); } public Manager GetManager() { Manager currentManager = null; for (int i = _managers.Count - 1; i >= 0; i--) { if (currentManager != null) { _managers[i].NextManager = currentManager; } currentManager = _managers[i]; } return currentManager; } }
5.LeaveContext.cs
/// <summary> /// 请假单 /// </summary> public class LeaveContext { /// <summary> /// 申请 /// </summary> public LeaveRequest Request { get; set; } /// <summary> /// 审批结果 /// </summary> public LeaveResponse Response { get; set; } }
6.LeaveRequest.cs
/// <summary> /// 请假申请 /// </summary> public class LeaveRequest { /// <summary> /// 申请人 /// </summary> public string Applicant { get; set; } /// <summary> /// 请假天数 /// </summary> public int LeaveDays { get; set; } /// <summary> /// 请假理由 /// </summary> public string Reason { get; set; } }
7.LeaveResponse.cs
/// <summary> /// 审批结果 /// </summary> public class LeaveResponse { /// <summary> /// 审批人 /// </summary> public string Approver { get; set; } /// <summary> /// 是否同意 /// </summary> public bool IsAgreed { get; set; } }
8.Program.cs
internal class Program { static void Main(string[] args) { LeaveContext context = new LeaveContext { Request = new LeaveRequest { Applicant = "张三", Reason = "世界那么大,我想去看看", LeaveDays = 2 } }; HR hR = new HR(); hR.AddManager(new TL("李四")); hR.AddManager(new PM("王五")); hR.AddManager(new CTO("赵六")); Manager manager = hR.GetManager(); manager.HandleRequest(context); if (context.Response == null) { Console.WriteLine($"{context.Request.LeaveDays}天假期太长,没人处理请假申请,请假失败"); } else { Console.WriteLine($"{context.Response.Approver}审批了{context.Request.Applicant}的{context.Request.LeaveDays}天请假申请,请假事由{context.Request.Reason}"); } } }
运行结果:
四、优缺点
优点
- 请求和处理分离,请求者可以不用知道是谁处理的,处理者可以不用知道请求的全貌,两者解耦,提高系统的灵活性。
缺点
- 性能不高;
- 调试不很方便。