在上一节的拦截器中提到,程序的设计者一般会用拦截器替替代动态代理,将动态代理的逻辑隐藏起来,而把拦截器接口提供给开发者,使开发者不需要关系动态代理的具体实现过程,但是有时候需要多个拦截器,而且拦截器之间会相互依赖,比如我们从公司的OA上提交一个请假单的时候,这个请假单会经过直接主管、部门经理、人力资源的层层审核,在请假被批准之前会被各级部门领导进行拦截,而且人力的审核依赖部门经理的审核结果,部门经理的审核又依赖直接主管的审核结果,这里的直接主管、部门经理和人力资源就像是三个拦截器,请假单这个对象在这一条拦截器链上进行传递,由此可以抽象地得出责任链模式的定义:
当一个对象在一条链上被多个拦截器拦截处理(拦截器也可以不处理)时,我们把这样的设计模式称为责任链模式,它用于一个对象在多个角色中传递的场景。---以上定义摘自《互联网轻量级框架整合开发》。
下面以员工请假为例,在请假单审核通过之前,需要被直接主管、部门经理和HR审核,这里面传递的对象是请假单,拦截器是三个领导。
第一步:创建审核请假单的拦截器接口
1 /* 2 * 定义一个审核请假单的拦截器接口 3 */ 4 public interface ExamineLeaveInteceptor { 5 //审批之前检查上一流程是否走完 6 public boolean before(Object proxy,Object target,Method method,Object[] args); 7 8 //如果上一个拦截器未处理完,则当前拦截器不予处理 9 public void around(Object proxy,Object target,Method method,Object[] args); 10 11 //审批之后签名 12 public void after(Object proxy,Object target,Method method,Object[] args); 13 }
第二步:创建三个拦截器类,实现上面定义的接口
1 /* 2 * 定义一个直接主管审核拦截器,实现审核请假单接口 3 */ 4 public class DirectorExamineInterceptor implements ExamineLeaveInteceptor { 5 public boolean before(Object proxy, Object target, Method method, Object[] args) { 6 boolean result = true; 7 System.out.println("主管同意之前检查信息是否填写完整"); 8 return result; 9 } 10 11 public void around(Object proxy, Object target, Method method, Object[] args) { 12 System.out.println("打回重新填写"); 13 14 } 15 16 public void after(Object proxy, Object target, Method method, Object[] args) { 17 System.out.println("审核完毕,主管签名"); 18 } 19 } 20 21 /* 22 * 部门经理审核拦截器 23 */ 24 public class ManagerExamineInterceptor implements ExamineLeaveInteceptor { 25 26 public boolean before(Object proxy, Object target, Method method, Object[] args) { 27 boolean result = true; 28 System.out.println("部门经理审核之前检查是否通过员工主管审核"); 29 return result; 30 } 31 32 public void around(Object proxy, Object target, Method method, Object[] args) { 33 System.out.println("员工主管没通过,部门经理不予审核"); 34 35 } 36 37 public void after(Object proxy, Object target, Method method, Object[] args) { 38 System.out.println("审核完毕,经理签名"); 39 } 40 41 } 42 43 * 44 * hr审核拦截器 45 */ 46 public class HrExamineInterceptor implements ExamineLeaveInteceptor { 47 48 public boolean before(Object proxy, Object target, Method method, Object[] args) { 49 boolean result = true; 50 System.out.println("hr审核之前检查部门经理是否通过"); 51 return result; 52 } 53 54 public void around(Object proxy, Object target, Method method, Object[] args) { 55 System.out.println("部门经理没通过,hr不予审核"); 56 57 } 58 59 public void after(Object proxy, Object target, Method method, Object[] args) { 60 System.out.println("审核完毕,hr签名"); 61 } 62 63 }
第三步:创建请假单类
1 /* 2 * 请假单类 3 */ 4 public class LeaveFile { 5 public String name; //请假单名称 6 public String userName; //请假人 7 public int leavel; //请假类型 8 9 public LeaveFile(String name, String userName, int leavel) { 10 this.name = name; 11 this.userName = userName; 12 this.leavel = leavel; 13 } 14 15 public String getName() { 16 return name; 17 } 18 19 public void setName(String name) { 20 this.name = name; 21 } 22 23 public String getUserName() { 24 return userName; 25 } 26 27 public void setUserName(String userName) { 28 this.userName = userName; 29 } 30 31 public int getLeavel() { 32 return leavel; 33 } 34 35 public void setLeavel(int leavel) { 36 this.leavel = leavel; 37 } 38 }
第四步:创建审核请假单接口及实现类
1 /* 2 * 审核请假单接口 3 */ 4 public interface ExamineLeaveInterface { 5 6 public void examine(LeaveFile file); 7 } 8 9 /* 10 * 审核请假单实现类 11 */ 12 public class ExamineLeaveInterfaceImpl implements ExamineLeaveInterface { 13 /** 14 * file:请假单 15 */ 16 public void examine(LeaveFile file) { 17 System.out.println("员工" + file.getUserName() + "的请假单审核完毕"); 18 } 19 }
第五步:创建动态代理类,代理真是对象方法
1 /* 2 * 动态代理类,代理拦截器方法 3 */ 4 public class DynamicProxyInterceptor implements InvocationHandler { 5 private Object target;// 真实对象 6 private String interceptorName;// 拦截器全限定名 7 8 public DynamicProxyInterceptor(Object target, String interceptorName) { 9 this.target = target; 10 this.interceptorName = interceptorName; 11 } 12 13 // 返回代理对象 14 public static Object bind(Object target, String interceptorName) { 15 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), 16 new DynamicProxyInterceptor(target, interceptorName)); 17 } 18 19 // 动态生成拦截器,并执行方法 20 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 21 if (interceptorName == null) { 22 return method.invoke(target, args); 23 } 24 25 Object result = null; 26 ExamineLeaveInteceptor examineInterceptor = (ExamineLeaveInteceptor) Class.forName(interceptorName) 27 .newInstance(); 28 // 如果拦截器中的before方法执行成功,则执行真实对象的方法,否则不能通过 29 if (examineInterceptor.before(proxy, target, method, args)) { 30 result = method.invoke(target, args); 31 examineInterceptor.after(proxy, target, method, args); 32 } else { 33 examineInterceptor.around(proxy, target, method, args); 34 } 35 return result; 36 } 37 38 }
第六步:申请请假
1 /* 2 * 用户提交请假单 3 */ 4 public class AskForLeave { 5 public static void main(String[] args) { 6 LeaveFile file = new LeaveFile("请假单", "张三", 0); 7 //获取直接主管动态代理对象 8 ExamineLeaveInterface directProxy = (ExamineLeaveInterface) DynamicProxyInterceptor.bind(new ExamineLeaveInterfaceImpl(),"com.daily.dutychain.DirectorExamineInterceptor"); 9 //获取部门经理动态代理对象,依赖直接主管 10 ExamineLeaveInterface managerProxy = (ExamineLeaveInterface) DynamicProxyInterceptor.bind(directProxy,"com.daily.dutychain.ManagerExamineInterceptor"); 11 //获取人力资源动态代理对象,依赖部门经理 12 ExamineLeaveInterface hrProxy = (ExamineLeaveInterface) DynamicProxyInterceptor.bind(managerProxy,"com.daily.dutychain.HrExamineInterceptor"); 13 hrProxy.examine(file); 14 15 } 16 }
第七步:查看执行结果
1 hr审核之前检查部门经理是否通过 2 部门经理审核之前检查是否通过员工主管审核 3 主管同意之前检查信息是否填写完整 4 员工张三的请假单审核完毕 5 审核完毕,主管签名 6 审核完毕,经理签名 7 审核完毕,hr签名
从结果可以看到,一个请假单需要经过不同层级的审核,最终才能通过,这就是责任链模式,每个拦截器负责自身人物的同时又要依赖上一级拦截器的处理结果。