职责链模式(Chain of Responsibility):
在现实生活中,常常会出现这样的事例:一个请求需要多个对象处理,但每个对象的处理条件或权限不同。如公司员工报销差旅费,可审批的领导有部分负责人、副总经理、总经理等,但每个领导能审批的金额是不同的,不同的金额需要找相应的领导审批,也就是说要报销必须先搞清楚需要谁来审批。职责链模式就是为了解决这样的问题产生的。
职责链模式,又叫责任链模式。是为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一个对象记住其下一个对象的引用而连成一条链。当发生请求时,可将请求沿着这条链传递,直到有对象处理它为止。
职责链模式的角色:
1)抽象处理者(Handler):声明了所有具体处理者的通用接口。 该接口通常仅包含单个方法用于请求处理, 但有时其还会包含一个设置链上下个处理者的方法
2)具体处理者(ConcreteHandler):包含处理请求的实际代码。 每个处理者接收到请求后, 都必须决定是否进行处理, 以及是否沿着链传递请求。处理者通常是独立且不可变的, 需要通过构造函数一次性地获得所有必要地数据。
3)请求信息(Request):定义请求的信息。
4)客户端(Client):可根据程序逻辑一次性或者动态地生成链。值得注意的是,请求可发送给链上的任意一个处理者,而非必须是第一个处理者。
责任链的实现:(以请假为例)
1 internal class Program 2 { 3 private static void Main(string[] args) 4 { 5 //构建各个领导人 6 Leader director = new Director("张三");//主任 7 Leader manager = new Manager("李四");//经理 8 Leader generalManager = new GeneralManager("王五");//总经理 9 //设置各个责任链上的关系 10 director.setNextLeader(manager);//主任的下一个审批人为经理 11 manager.setNextLeader(generalManager);//经理的下一个审批人为总经理 12 13 //开始请假 14 LeaveRequest request = new LeaveRequest("小明", 5, "旅游"); 15 director.HandleRequest(request);//小明提交了请假申请给主任 16 } 17 } 18 19 /// <summary> 20 /// 请假的信息 21 /// </summary> 22 public class LeaveRequest 23 { 24 public string EmplName { get; set; } 25 public int LeaveDays { get; set; } 26 public string Reason { get; set; } 27 28 public LeaveRequest(string emplName, int leaveDays, string reason) 29 { 30 this.EmplName = emplName; 31 this.LeaveDays = leaveDays; 32 this.Reason = reason; 33 } 34 } 35 36 /// <summary> 37 /// 管理责任链上的对象处理的抽象类 38 /// </summary> 39 public abstract class Leader 40 { 41 protected string name; 42 protected Leader nextLeader;//下一个继承者 43 44 public Leader(string name) 45 { 46 this.name = name; 47 } 48 49 /// <summary> 50 /// 设置责任链上的下一个继承者 51 /// </summary> 52 /// <param name="leader"></param> 53 public void setNextLeader(Leader leader) 54 { 55 this.nextLeader = leader; 56 } 57 58 /// <summary> 59 /// 处理请求的抽象方法 60 /// </summary> 61 /// <param name="leader"></param> 62 public abstract void HandleRequest(LeaveRequest leader); 63 } 64 65 /// <summary> 66 /// 主任: 处理小于等于3天的假期 67 /// </summary> 68 public class Director : Leader 69 { 70 public Director(string name) 71 : base(name) 72 { 73 } 74 75 /// <summary> 76 /// 责任链上对象对请求的具体处理 77 /// </summary> 78 /// <param name="leader"></param> 79 public override void HandleRequest(LeaveRequest leader) 80 { 81 if (leader.LeaveDays <= 3) 82 { 83 Console.WriteLine($"请假人:{leader.EmplName},天数{leader.LeaveDays},理由:{leader.Reason}"); 84 Console.WriteLine($"审批人:{this.name } 主任,审批通过!"); 85 } 86 else 87 { 88 if (this.nextLeader != null) 89 { 90 this.nextLeader.HandleRequest(leader); 91 } 92 } 93 } 94 } 95 96 /// <summary> 97 /// 经理: 处理大于3天,小于等于10天的假期 98 /// </summary> 99 public class Manager : Leader 100 { 101 public Manager(string name) 102 : base(name) 103 { 104 } 105 106 /// <summary> 107 /// 责任链上对象对请求的具体处理 108 /// </summary> 109 /// <param name="leader"></param> 110 public override void HandleRequest(LeaveRequest leader) 111 { 112 if (leader.LeaveDays > 3 && leader.LeaveDays <= 10) 113 { 114 Console.WriteLine($"请假人:{leader.EmplName},天数{leader.LeaveDays},理由:{leader.Reason}"); 115 Console.WriteLine($"审批人:{this.name } 经理,审批通过!"); 116 } 117 else 118 { 119 if (this.nextLeader != null) 120 { 121 this.nextLeader.HandleRequest(leader); 122 } 123 } 124 } 125 } 126 127 /// <summary> 128 /// 总经理: 处理大于10天,小于等于30天的请假信息 129 /// </summary> 130 public class GeneralManager : Leader 131 { 132 public GeneralManager(string name) 133 : base(name) 134 { 135 } 136 137 /// <summary> 138 /// 责任链上对象对请求的具体处理 139 /// </summary> 140 /// <param name="leader"></param> 141 public override void HandleRequest(LeaveRequest leader) 142 { 143 if (leader.LeaveDays > 10 && leader.LeaveDays <= 30) 144 { 145 Console.WriteLine($"请假人:{leader.EmplName},天数{leader.LeaveDays},理由:{leader.Reason}"); 146 Console.WriteLine($"审批人:{this.name } 总经理,审批通过!"); 147 } 148 else 149 { 150 if (this.nextLeader != null) 151 { 152 this.nextLeader.HandleRequest(leader); 153 } 154 else 155 { 156 Console.WriteLine($"你疯了!!!"); 157 } 158 } 159 } 160 }
从实现上可以看出,每个领导只处理自己能力范围内的事情,不是自己的坚决不处理;同时职责链是动态构建的,下一个处理者由调用者自己设置;缺少处理对象可以直接添加,符合开闭原则。
职责链的优缺点:
优点:
1)请求者和接收者松耦合。在职责链模式中,请求者并不知道接收者是谁,也不知道具体如何处理,请求者只是负责向职责链发送请求就可以了。而每个职责对象也不用管请求者或者是其他的职责对象,只负责处理自己的部分,其他的就交给其他的职责对象去处理。也就是说,请求者和接受者是完全解耦的。
2)动态组合职责。职责链模式会把功能处理分散到单独的职责对象中,然后再使用的时候,可以动态组合职责形成职责链,从而可以灵活地给对象分配职责,也可以灵活地实现和改变对象的职责。
3)减少代码中的if..else..判断,优化代码。
缺点:
1)产生很多细粒度对象。职责链模式会把功能处理分散到单独的职责对象中,也就是每个职责对象只处理一个方面的功能,要把整个业务处理完,需要很多职责对象的组合,这样会产生大量的细粒度职责对象。
2)不一定能被处理。职责链模式的每个职责对象只负责自己处理的那一部分,因此可能会出现某个请求把整个链传递完了都没有职责对象处理它。这就需要使用职责链模式的时候,需要提供默认的处理,并且注意构造的链的有效性。
3)职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能由于职责链的错误设置而导致系统出错,如可能会造成循环调用。
职责链的应用场景:
1)有多个对象可以处理一个请求,哪个对象处理该请求由运行时刻自动确定。
2)可动态指定一组对象处理请求,或添加新的处理者。
3)在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求。