设计模式-职责链模式(ChainOfResponsibility)
讲故事
书接上文,完美解决了多判断分支分支问题,符合了我的第一、第三条。今天来探讨一下状态模式异父异母的亲兄弟职责链模式,它们都有异曲同工之妙,实际开发中可根据口味,自行选用。
今天的故事背景就放在我们平时 申请加薪、请假等活动中,我们都知道,随着我们申请内容的不同,审批人员的等级也不同。我们就先用最简单的代码模拟一下
coding
requesttype枚举,规范我们申请的类型
/// <summary> /// 请求类型 /// </summary> public enum requesttype { /// <summary> /// 请假 /// </summary> leave, /// <summary> /// 加薪 /// </summary> payrise }
requset类,简单描述申请内容
/// <summary> /// 请求 /// </summary> public class requset { /// <summary> /// 请求类型 /// </summary> public requesttype type { get; set; } /// <summary> /// 请求数量 /// </summary> public int number { get; set; } /// <summary> /// 请求说明 /// </summary> public string content { get { switch (type) { case requesttype.leave: return $"请假{number}天"; case requesttype.payrise: return $"加薪{number}元"; default: return "未知"; } } } }
managertype枚举,定义不同的审批人员类型
/// <summary> /// 管理者类型 /// </summary> public enum managertype { pm, cto, ceo }
manager类,审批人员,处理我们的请求
public class manager { private readonly managertype _managertype; public manager(managertype managertype) { _managertype = managertype; } /// <summary> /// 处理请求 /// </summary> public void process(requset requset) { if (_managertype == managertype.pm) { if (requset.type == requesttype.leave && requset.number <= 2) { console.writeline($"项目经理 已批准 你的 {requset.content} 申请"); } else { console.writeline($"项目经理 无权批准 你的 {requset.content} 申请"); } } else if (_managertype == managertype.cto) { if (requset.type == requesttype.leave) { if (requset.number <= 5) { console.writeline($"cto 已批准 你的 {requset.content} 申请"); } else { console.writeline($"cto 无权批准 你的 {requset.content} 申请"); } } else { if (requset.number <= 500) { console.writeline($"cto 已批准 你的 {requset.content} 申请"); } else { console.writeline($"cto 无权批准 你的 {requset.content} 申请"); } } } else if (_managertype == managertype.ceo) { if (requset.type == requesttype.leave) { console.writeline($"ceo 已批准 你的 {requset.content} 申请"); } else { if (requset.number <= 1000) { console.writeline($"ceo 已批准 你的 {requset.content} 申请"); } else { console.writeline($"ceo对你的 {requset.content} 申请 说:“小子,你有点飘啊!”"); } } } } }
客户端
internal class program { private static void main(string[] args) { //创建领导 var pm = new manager(managertype.pm); var cto = new manager(managertype.cto); var ceo = new manager(managertype.ceo); //创建 请假请求 var request1 = new requset { type = requesttype.leave, number = 5 }; pm.process(request1); cto.process(request1); ceo.process(request1); console.writeline("\n"); //创建 加薪请求 var request2 = new requset { type = requesttype.payrise, number = 2000 }; pm.process(request2); cto.process(request2); ceo.process(request2); console.writeline("\nhappy ending~"); console.readline(); } }
结果展示:
项目经理 无权批准 你的 请假5天 申请 cto 已批准 你的 请假5天 申请 ceo 已批准 你的 请假5天 申请 项目经理 无权批准 你的 加薪2000元 申请 cto 无权批准 你的 加薪2000元 申请 ceo对你的 加薪2000元 申请 说:“小子,你有点飘啊!”
我们code review后,就会发现manager.process()又丑又长呀,同样是出现的三个问题:方法长,分支多,难维护。
那我们怎么使用职责链模式来解决呢?我们先来了解一下它...
职责链模式
敲黑板·划重点
定义: 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一个链,并沿着这条链传递请求,知道有一个对象处理请求为止。
好处: 接收者和发送者都没有对方的明确信息,且链中的对象自己也并不知道链的结构。结果是职责链可简化对象的相互连接,它们仅需保持一个指向其后继者的引用,而不需要保持它所有的候选接受者的引用。【降低耦合度】
注意: 一个请求极有可能到了链的末端都得不到处理,或者因为没有正确配置而得不到处理,需要考虑全面!
在下面代码优化中来深化对定义、好处的理解吧
code upgrade
manager抽象类,不同权限审批人员的基类,可以设置下一级审批人员,形成一条职责链
public abstract class manager { protected readonly managertype _managertype; /// <summary> /// 下一个处理者 /// </summary> protected manager successor { get; private set; } public manager(managertype managertype) { _managertype = managertype; } /// <summary> /// 设置下一个处理者 /// </summary> /// <param name="manager"></param> public void setsuccessor(manager manager) { successor = manager; } /// <summary> /// 处理请求 /// </summary> /// <param name="requset"></param> public abstract void process(requset requset); }
pm、cto、ceo类,具体的审批人,实现处理方法process()
public class pm : manager { public pm(managertype managertype) : base(managertype) { } public override void process(requset requset) { if (requset.type == requesttype.leave && requset.number <= 2) { console.writeline($"项目经理 已批准 你的 {requset.content} 申请"); return; } if (successor != null) { //交由下一级处理 successor.process(requset); } } } public class cto : manager { public cto(managertype managertype) : base(managertype) { } public override void process(requset requset) { if (requset.type == requesttype.leave && requset.number <= 5) { console.writeline($"cto 已批准 你的 {requset.content} 申请"); return; } if (requset.type == requesttype.payrise && requset.number <= 500) { console.writeline($"cto 已批准 你的 {requset.content} 申请"); return; } if (successor != null) { //交由下一级处理 successor.process(requset); } } } public class ceo : manager { public ceo(managertype managertype) : base(managertype) { } public override void process(requset requset) { if (requset.type == requesttype.leave && requset.number <= 15) { console.writeline($"ceo 已批准 你的 {requset.content} 申请"); return; } if (requset.type == requesttype.payrise && requset.number <= 1000) { console.writeline($"ceo 已批准 你的 {requset.content} 申请"); return; } console.writeline($"ceo对你的 {requset.content} 申请 说:“小子,你有点飘啊!”"); } }
客户端代码
internal class program { private static void main(string[] args) { //创建领导 var pm = new pm(managertype.pm); var cto = new cto(managertype.cto); var ceo = new ceo(managertype.ceo); //设置下一级处理者 pm.setsuccessor(cto); cto.setsuccessor(ceo); //创建 请假请求 var request1 = new requset { type = requesttype.leave, number = 5 }; pm.process(request1); console.writeline("\n"); //创建 加薪请求 var request2 = new requset { type = requesttype.payrise, number = 2000 }; pm.process(request2); console.writeline("\nhappy ending~"); console.readline(); } }
结果展示:
cto 已批准 你的 请假5天 申请 ceo对你的 加薪2000元 申请 说:“小子,你有点飘啊!”
这样我们也消除上面三个问题。当需求需要人事加入审批流程时,只需要增加一个继承manager的人事类;当需求要求不需要cto审批,直接由pm转到ceo时,我们只用修改pm的setsuccessor(),这也体现了职责链的灵活性。
示例代码地址: https://gitee.com/sayook/designmode/tree/master/chainofresponsibility
上一篇: LeetCode--最长公共前缀