• 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签名

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

  • 相关阅读:
    不使用spring的情况下用java原生代码操作mongodb数据库的两种方式
    log4j配置输出到多个日志文件
    HIDL概述【转】
    Android HIDL学习(2) ---- HelloWorld【转】
    第2课第7节_Java面向对象编程_内部类_P【学习笔记】
    SDM439平台出现部分机型SD卡不能识别mmc1: error -110 whilst initialising SD card【学习笔记】
    第2课第6节_Java面向对象编程_包和权限_P【学习笔记】
    Android A/B System OTA分析(一)概览【转】
    查看DDR的频率【学习笔记】
    音频参数路径【学习笔记】
  • 原文地址:https://www.cnblogs.com/hellowhy/p/9645289.html
Copyright © 2020-2023  润新知