基本介绍:
“责任链”顾名思义,是指一个需要负责处理请求的链条。
每个链条节点都是一个单独的责任者,由责任者自己决定是否处理请求或交给下一个节点。
在设计模式中的解释则为:为请求创建了一个接收者对象的链。适用于有多个对象可以处理同一个请求,但具体由哪个对象处理则在运行时动态决定的情况。
俗话说起来就是一群领导组成了一个上下级链路关系,每个领导的职责各不相同,老百姓办事情的时候肯定没办法知道该找哪个领导。
这个时候就可以把需要办的事情交给接待人员,由接待人员自行判断是不是可以处理或者交给上级处理,至于是谁给我负责,那我这个小老百姓并不关心,只要办了就可以了。
老百姓办的事情就是请求,接待人员和领导群组成的集合就是责任链,每个领导负责自己的职责,至于最后是谁负责,那就根据具体事情一级一级的传递动态决定。
这么做的好处也显而易见,我的请求可以是任意的,具体要不要解决由谁解决,都交给责任链自己去判断。
举例说明:
公司的请假系统,当一个员工提交请假申请时,根据请假天数和职位的不同,需要由不同等级的领导审批。
项目组长》部门经理》总经理》董事长》董事会就组成了一个责任链。
普通员工和项目组长都是请假1天,但是由谁负责审批,交给责任链就可以了,由责任链自己决定由谁去审批。
比如普通员工请假1天,只需要交给项目组长审批就可以。但如果是项目组长请假1天,需要交给部门经理审批。
这种直接有单个责任人负责处理的称为纯的职责链模式,
一个请求必须被某一个处理者对象所接收,且一个具体处理者对某个请求的处理只能采用以下两种行为之一:自己处理或把责任提交给上级处理。
如果普通员工请假1个月,项目组长一般没有直接审批的权限,需要先由项目组成初步审批,再由项目组长提交给部门经理进行审批。
这种单个责任人负责部分责任的情况称为不纯的职责链模式,
允许出现某一个具体处理者对象在承担了请求的一部分责任后又将剩余的责任传给上级的情况,且一个请求可以最终不被任何接收端对象所接收。
在一个纯的职责链模式里面,一个请求必须被某一个处理者对象所接收;
在一个不纯的职责链模式里面,一个请求可以被多个处理者对象所处理或最终不被任何接收端对象所接收。
基本结构:
抽象处理者角色:它定义一个处理请求的接口或抽象类,由于不同的具体处理者处理请求的方式不一样,因此在其中定义一个抽象的处理方法。同时该类需要维持一个指向上级的引用,通过该引用,处理者可以连成一条线。
具体处理者角色:继承自抽象类,具体实现处理方法,在处理方法中进行处理或不满足职责向上级转发请求。
客户端角色:负责链路组合顺序。
请求者角色:构建请求对象。一般通过参数方式注入到具体处理类中。
优缺点:
优点:
- 降低了对象之间的耦合度。该模式使得一个对象无须知道到底是哪一个对象处理其请求以及链的结构,发送者和接收者也无须拥有对方的明确信息。
- 增强了系统的可扩展性。可以根据需要增加新的请求处理类,满足开闭原则。
- 增强了给对象指派职责的灵活性。当工作流程发生变化,可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。
- 责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。
- 责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
缺点:
- 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
- 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
- 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。
具体实例:
1 ///2 /// 请假条类 3 /// 4 public class LeaveRequest 5 { 6 //请假人 7 public string Name { get; set; } 8 9 //请假天数 10 public int RestDaySum { get; set; } 11 12 //职业等级 13 public int Grade { get; set; } 14 15 //构造函数中初始化请假信息 16 public LeaveRequest(string strName, int iRestDaySum, int iGrade) 17 { 18 Name = strName; 19 RestDaySum = iRestDaySum; 20 Grade = iGrade; 21 } 22 } 23 24 /// 25 /// 抽象类 26 /// 27 public abstract class Approver 28 { 29 public Approver() 30 { 31 SetGrade(); 32 } 33 //下一责任人引用 34 protected Approver _Approver; 35 36 //职业等级 37 protected int Grade { get; set; } 38 39 //设置下一个审批人,用来形成链路 40 public void SetNextApprover(Approver approver) 41 { 42 this._Approver = approver; 43 } 44 45 //设置职业等级 46 public abstract void SetGrade(); 47 48 //处理请求 49 public abstract void ProcessRequest(LeaveRequest leaveRequest); 50 } 51 52 /// 53 /// 具体实现类---组长 54 /// 55 public class GroupLeader : Approver 56 { 57 public override void ProcessRequest(LeaveRequest leaveRequest) 58 { 59 if (leaveRequest.Grade >= this.Grade) 60 { 61 Console.WriteLine(leaveRequest.Name + "的请假条,组长无权处置!交由上级审核!"); 62 _Approver.ProcessRequest(leaveRequest); 63 } 64 else 65 { 66 if (leaveRequest.RestDaySum > 3) 67 { 68 Console.WriteLine(leaveRequest.Name + "的请假条,请假天数超出组长的职权,交由上级审核!"); 69 _Approver.ProcessRequest(leaveRequest); 70 } 71 else 72 { 73 Console.WriteLine(leaveRequest.Name + "的请假条,经由组长审核通过,批准休假。"); 74 } 75 } 76 } 77 78 public override void SetGrade() 79 { 80 this.Grade = 2; 81 } 82 } 83 84 /// 85 /// 具体实现类---部门经理 86 /// 87 public class Manager : Approver 88 { 89 public override void ProcessRequest(LeaveRequest leaveRequest) 90 { 91 if (leaveRequest.Grade >= this.Grade) 92 { 93 Console.WriteLine(leaveRequest.Name + "的请假条,部门经理无权处置!交由上级审核!"); 94 _Approver.ProcessRequest(leaveRequest); 95 } 96 else 97 { 98 if (leaveRequest.RestDaySum > 7) 99 {100 Console.WriteLine(leaveRequest.Name + "的请假条,请假天数超出部门经理的职权,交由上级审核!");101 _Approver.ProcessRequest(leaveRequest);102 }103 else104 {105 Console.WriteLine(leaveRequest.Name + "的请假条,经由部门经理审核通过,批准休假。");106 }107 }108 }109 110 public override void SetGrade()111 {112 this.Grade = 3;113 }114 }115 116 /// 117 /// 具体实现类---总经理118 /// 119 public class GeneralManager : Approver120 {121 public override void ProcessRequest(LeaveRequest leaveRequest)122 {123 if (leaveRequest.Grade >= this.Grade)124 {125 Console.WriteLine(leaveRequest.Name + "的请假条,总经理无权处置!交由上级审核!");126 _Approver.ProcessRequest(leaveRequest);127 }128 else129 {130 if (leaveRequest.RestDaySum > 30)131 {132 Console.WriteLine(leaveRequest.Name + "的请假条,请假天数超出总经理的职权,交由上级审核!");133 _Approver.ProcessRequest(leaveRequest);134 }135 else136 {137 Console.WriteLine(leaveRequest.Name + "的请假条,经由总经理审核通过,批准休假。");138 }139 }140 }141 142 public override void SetGrade()143 {144 this.Grade = 4;145 }146 }147 148 /// 149 /// 客户端150 /// 151 class Client152 {153 static void Main(string[] args)154 {155 //创建组长责任人156 Approver groupLeader = new GroupLeader();157 //创建部门经理责任人158 Approver manager = new Manager();159 //创建总经理责任人160 Approver generalManager = new GeneralManager();161 162 //设置组长的上级为部门经理163 groupLeader.SetNextApprover(manager);164 //设置部门经理的上级为总经理165 manager.SetNextApprover(generalManager);166 167 //通过以上操作构建了责任链168 169 //创建请求---请假条---普通职员张三请假3天170 LeaveRequest leaveRequest = new LeaveRequest("张三", 3, 1);171 //将请假条交给责任链起始端172 groupLeader.ProcessRequest(leaveRequest);173 Console.WriteLine("\r\n");174 175 //创建请求---请假条---部门经理李四请假3天176 leaveRequest = new LeaveRequest("李四", 3, 3);177 //将请假条交给责任链起始端178 groupLeader.ProcessRequest(leaveRequest);179 Console.WriteLine("\r\n");180 181 182 //创建请求---请假条---普通职员小王请假7天183 leaveRequest = new LeaveRequest("小王", 7, 1);184 //将请假条交给责任链起始端185 groupLeader.ProcessRequest(leaveRequest);186 Console.WriteLine("\r\n");187 188 //如果知道链条的初始端可以不用从最开始端进行189 //创建请求---请假条---组长老刘请假3天190 leaveRequest = new LeaveRequest("老刘", 3, 2);191 //将请假条交给责任链中的部门经理192 manager.ProcessRequest(leaveRequest);193 Console.WriteLine("\r\n");194 195 Console.ReadKey();196 }197 }
总结:
责任链模式属于行为型模式。它使多个对象都有机会处理请求,从而避免发送者和接受者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。