Java内功修炼系列一责任链模式

在上一节的拦截器中提到,程序的设计者一般会用拦截器替替代动态代理,将动态代理的逻辑隐藏起来,而把拦截器接口提供给开发者,使开发者不需要关系动态代理的具体实现过程,但是有时候需要多个拦截器,而且拦截器之间会相互依赖,比如我们从公司的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签名

从结果可以看到,一个请假单需要经过不同层级的审核,最终才能通过,这就是责任链模式,每个拦截器负责自身人物的同时又要依赖上一级拦截器的处理结果。

posted @ 2018-09-14 11:25  bug改了我  阅读(247)  评论(0编辑  收藏  举报