GOF23设计模式之责任链模式(chain of responsibility)
一、责任链模式概述
将能够处理同一类请求的对象连成一条链,所提交的请求沿着链传递,链上的对象逐个判断是否有能力处理该请求。
如果能则处理,否则传递给链上的下一个对象去处理。
定义责任链
(1)通过链表的方式实现职责链
(2)通过非链表的方式实现职责链
通过集合、数组生成职责链更加实用!实际上,很多项目中,每个具体的Handler并不是由开发团队定义的,而是项目上线后由外部单位追加的,所以使用链表方式定义责任链(COR)就很困难!
二、责任链模式场景
(1)公司里面,请假条审批过程:
① 如果请假天数小于3天,主任审批
② 如果请假天数大于等于3天,小于10天,经理审批
③ 如果请假天数大于等于10天,小于30天,总经理审批
④ 如果请假天数大于等于30天,提示拒绝
(2)添加新的处理对象:
可以在流程中增加新的“副总经理”角色,审批大于等于10天,小于20天的情况。
① 如果请假天数小于3天,主任审批
② 如果请假天数大于等于3天,小于10天,经理审批
③【增加】如果请假天数大于等于10天,小于20天,副总经理审批
④ 如果请假天数大于等于20天,小于30天,总经理审批
⑤ 如果请假天数大于等于30天,提示拒绝
三、使用责任链模式模拟公司请假流程
1 /** 2 * 封装请假的基本信息 3 * @author CL 4 * 5 */ 6 public class LeaveRequest { 7 /** 8 * 员工姓名 9 */ 10 private String empName; 11 /** 12 * 请假天数 13 */ 14 private int leaveDays; 15 /** 16 * 请假事由 17 */ 18 private String reason; 19 20 public LeaveRequest() { 21 } 22 23 public LeaveRequest(String empName, int leaveDays, String reason) { 24 this.empName = empName; 25 this.leaveDays = leaveDays; 26 this.reason = reason; 27 } 28 29 public String getEmpName() { 30 return empName; 31 } 32 33 public void setEmpName(String empName) { 34 this.empName = empName; 35 } 36 37 public int getLeaveDays() { 38 return leaveDays; 39 } 40 41 public void setLeaveDays(int leaveDays) { 42 this.leaveDays = leaveDays; 43 } 44 45 public String getReason() { 46 return reason; 47 } 48 49 public void setReason(String reason) { 50 this.reason = reason; 51 } 52 53 }
1 /** 2 * 抽象类(领导) 3 * @author CL 4 * 5 */ 6 public abstract class Leader { 7 protected String name; 8 /** 9 * 责任链上的后继对象 10 */ 11 protected Leader nextLeader; 12 13 public Leader(String name) { 14 this.name = name; 15 } 16 17 /** 18 * 设定责任链上的后即对象 19 * @param nextLeader 20 */ 21 public void setNextLeader(Leader nextLeader) { 22 this.nextLeader = nextLeader; 23 } 24 25 /** 26 * 处理请假请求的核心业务方法 27 * @param leaveRequest 28 */ 29 public abstract void handlerRequest(LeaveRequest leaveRequest); 30 31 32 }
1 /** 2 * 主任 3 * @author CL 4 * 5 */ 6 public class Director extends Leader { 7 8 public Director(String name) { 9 super(name); 10 } 11 12 @Override 13 public void handlerRequest(LeaveRequest leaveRequest) { 14 if (leaveRequest.getLeaveDays() < 3) { 15 System.out.println("员工:"+leaveRequest.getEmpName()+",请假:" 16 +leaveRequest.getLeaveDays()+"天,理由:"+leaveRequest.getReason()); 17 System.out.println("主任:"+this.name+",审批通过!"); 18 } else { //责任链上的后继对象处理 19 if (this.nextLeader != null) { 20 this.nextLeader.handlerRequest(leaveRequest); 21 } 22 } 23 } 24 25 }
1 /** 2 * 经理 3 * @author CL 4 * 5 */ 6 public class Manager extends Leader { 7 8 public Manager(String name) { 9 super(name); 10 } 11 12 @Override 13 public void handlerRequest(LeaveRequest leaveRequest) { 14 if (leaveRequest.getLeaveDays() < 10) { 15 System.out.println("员工:"+leaveRequest.getEmpName()+",请假:" 16 +leaveRequest.getLeaveDays()+"天,理由:"+leaveRequest.getReason()); 17 System.out.println("经理:"+this.name+",审批通过!"); 18 } else { //责任链上的后继对象处理 19 if (this.nextLeader != null) { 20 this.nextLeader.handlerRequest(leaveRequest); 21 } 22 } 23 } 24 25 }
1 /** 2 * 副总经理 3 * @author CL 4 * 5 */ 6 public class ViceGeneraManager extends Leader { 7 8 public ViceGeneraManager(String name) { 9 super(name); 10 } 11 12 @Override 13 public void handlerRequest(LeaveRequest leaveRequest) { 14 if (leaveRequest.getLeaveDays() < 20) { 15 System.out.println("员工:"+leaveRequest.getEmpName()+",请假:" 16 +leaveRequest.getLeaveDays()+"天,理由:"+leaveRequest.getReason()); 17 System.out.println("副总经理:"+this.name+",审批通过!"); 18 } else { //责任链上的后继对象处理 19 if (this.nextLeader != null) { 20 this.nextLeader.handlerRequest(leaveRequest); 21 } 22 } 23 } 24 25 }
1 /** 2 * 总经理 3 * @author CL 4 * 5 */ 6 public class GeneraManager extends Leader { 7 8 public GeneraManager(String name) { 9 super(name); 10 } 11 12 @Override 13 public void handlerRequest(LeaveRequest leaveRequest) { 14 if (leaveRequest.getLeaveDays() < 30) { 15 System.out.println("总经理:"+leaveRequest.getEmpName()+",请假:" 16 +leaveRequest.getLeaveDays()+"天,理由:"+leaveRequest.getReason()); 17 System.out.println("主任:"+this.name+",审批通过!"); 18 } else { //无责任链上的后继对象 19 System.out.println("员工:"+leaveRequest.getEmpName()+",请假天数:" 20 +leaveRequest.getLeaveDays()+"天,超过30天,不予请假!"); 21 } 22 } 23 24 }
测试:
1 /** 2 * 测试责任链模式 3 * @author CL 4 * 5 */ 6 public class Client { 7 8 public static void main(String[] args) { 9 Leader a = new Director("张主任"); 10 Leader b = new Manager("李经理"); 11 Leader c = new ViceGeneraManager("王副总经理"); 12 Leader d = new GeneraManager("赵总经理"); 13 14 //构建责任链 15 a.setNextLeader(b); 16 b.setNextLeader(c); 17 c.setNextLeader(d); 18 19 //请假 20 LeaveRequest req1 = new LeaveRequest("Tom", 2, "生病"); 21 LeaveRequest req2 = new LeaveRequest("Jame", 15, "回家"); 22 LeaveRequest req3 = new LeaveRequest("Rose", 25, "调休"); 23 LeaveRequest req4 = new LeaveRequest("Jack", 35, "闹着玩"); 24 25 //审批 26 a.handlerRequest(req1); 27 a.handlerRequest(req2); 28 a.handlerRequest(req3); 29 a.handlerRequest(req4); 30 } 31 }
控制台输出:
员工:Tom,请假:2天,理由:生病
主任:张主任,审批通过!
员工:Jame,请假:15天,理由:回家
副总经理:王副总经理,审批通过!
总经理:Rose,请假:25天,理由:调休
主任:赵总经理,审批通过!
员工:Jack,请假天数:35天,超过30天,不予请假!
四、责任链模式常见开发应用场景
(1)Java 中,异常处理机制就是一种责任链模式。一个 try 可以对应多个 catch,当第一个 catch 不匹配类型,则自动跳到第二个 catch;
(2)JavaScript 语言中,事件的冒泡和捕获机制(Java 语言中事件的处理采用观察者模式);
(3)Servlet 开发中,过滤器的链式处理;
(4)Struts2 中,拦截器的调用也是典型的责任链模式;
(5)…………