在上一节的拦截器中提到,程序的设计者一般会用拦截器替替代动态代理,将动态代理的逻辑隐藏起来,而把拦截器接口提供给开发者,使开发者不需要关系动态代理的具体实现过程,但是有时候需要多个拦截器,而且拦截器之间会相互依赖,比如我们从公司的OA上提交一个请假单的时候,这个请假单会经过直接主管、部门经理、人力资源的层层审核,在请假被批准之前会被各级部门领导进行拦截,而且人力的审核依赖部门经理的审核结果,部门经理的审核又依赖直接主管的审核结果,这里的直接主管、部门经理和人力资源就像是三个拦截器,请假单这个对象在这一条拦截器链上进行传递,由此可以抽象地得出责任链模式的定义:

当一个对象在一条链上被多个拦截器拦截处理(拦截器也可以不处理)时,我们把这样的设计模式称为责任链模式,它用于一个对象在多个角色中传递的场景。---以上定义摘自《互联网轻量级框架整合开发》。

下面以员工请假为例,在请假单审核通过之前,需要被直接主管、部门经理和HR审核,这里面传递的对象是请假单,拦截器是三个领导。

第一步:创建审核请假单的拦截器接口

 /*
* 定义一个审核请假单的拦截器接口
*/
public interface ExamineLeaveInteceptor {
//审批之前检查上一流程是否走完
public boolean before(Object proxy,Object target,Method method,Object[] args); //如果上一个拦截器未处理完,则当前拦截器不予处理
public void around(Object proxy,Object target,Method method,Object[] args); //审批之后签名
public void after(Object proxy,Object target,Method method,Object[] args);
}

第二步:创建三个拦截器类,实现上面定义的接口

 /*
* 定义一个直接主管审核拦截器,实现审核请假单接口
*/
public class DirectorExamineInterceptor implements ExamineLeaveInteceptor {
public boolean before(Object proxy, Object target, Method method, Object[] args) {
boolean result = true;
System.out.println("主管同意之前检查信息是否填写完整");
return result;
} public void around(Object proxy, Object target, Method method, Object[] args) {
System.out.println("打回重新填写"); } public void after(Object proxy, Object target, Method method, Object[] args) {
System.out.println("审核完毕,主管签名");
}
} /*
* 部门经理审核拦截器
*/
public class ManagerExamineInterceptor implements ExamineLeaveInteceptor { public boolean before(Object proxy, Object target, Method method, Object[] args) {
boolean result = true;
System.out.println("部门经理审核之前检查是否通过员工主管审核");
return result;
} public void around(Object proxy, Object target, Method method, Object[] args) {
System.out.println("员工主管没通过,部门经理不予审核"); } public void after(Object proxy, Object target, Method method, Object[] args) {
System.out.println("审核完毕,经理签名");
} } *
* hr审核拦截器
*/
public class HrExamineInterceptor implements ExamineLeaveInteceptor { public boolean before(Object proxy, Object target, Method method, Object[] args) {
boolean result = true;
System.out.println("hr审核之前检查部门经理是否通过");
return result;
} public void around(Object proxy, Object target, Method method, Object[] args) {
System.out.println("部门经理没通过,hr不予审核"); } public void after(Object proxy, Object target, Method method, Object[] args) {
System.out.println("审核完毕,hr签名");
} }

第三步:创建请假单类

 /*
* 请假单类
*/
public class LeaveFile {
public String name; //请假单名称
public String userName; //请假人
public int leavel; //请假类型 public LeaveFile(String name, String userName, int leavel) {
this.name = name;
this.userName = userName;
this.leavel = leavel;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getUserName() {
return userName;
} public void setUserName(String userName) {
this.userName = userName;
} public int getLeavel() {
return leavel;
} public void setLeavel(int leavel) {
this.leavel = leavel;
}
}

第四步:创建审核请假单接口及实现类

 /*
* 审核请假单接口
*/
public interface ExamineLeaveInterface { public void examine(LeaveFile file);
} /*
* 审核请假单实现类
*/
public class ExamineLeaveInterfaceImpl implements ExamineLeaveInterface {
/**
* file:请假单
*/
public void examine(LeaveFile file) {
System.out.println("员工" + file.getUserName() + "的请假单审核完毕");
}
}

第五步:创建动态代理类,代理真是对象方法

 /*
* 动态代理类,代理拦截器方法
*/
public class DynamicProxyInterceptor implements InvocationHandler {
private Object target;// 真实对象
private String interceptorName;// 拦截器全限定名 public DynamicProxyInterceptor(Object target, String interceptorName) {
this.target = target;
this.interceptorName = interceptorName;
} // 返回代理对象
public static Object bind(Object target, String interceptorName) {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
new DynamicProxyInterceptor(target, interceptorName));
} // 动态生成拦截器,并执行方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (interceptorName == null) {
return method.invoke(target, args);
} Object result = null;
ExamineLeaveInteceptor examineInterceptor = (ExamineLeaveInteceptor) Class.forName(interceptorName)
.newInstance();
// 如果拦截器中的before方法执行成功,则执行真实对象的方法,否则不能通过
if (examineInterceptor.before(proxy, target, method, args)) {
result = method.invoke(target, args);
examineInterceptor.after(proxy, target, method, args);
} else {
examineInterceptor.around(proxy, target, method, args);
}
return result;
} }

第六步:申请请假

 /*
* 用户提交请假单
*/
public class AskForLeave {
public static void main(String[] args) {
LeaveFile file = new LeaveFile("请假单", "张三", 0);
//获取直接主管动态代理对象
ExamineLeaveInterface directProxy = (ExamineLeaveInterface) DynamicProxyInterceptor.bind(new ExamineLeaveInterfaceImpl(),"com.daily.dutychain.DirectorExamineInterceptor");
//获取部门经理动态代理对象,依赖直接主管
ExamineLeaveInterface managerProxy = (ExamineLeaveInterface) DynamicProxyInterceptor.bind(directProxy,"com.daily.dutychain.ManagerExamineInterceptor");
//获取人力资源动态代理对象,依赖部门经理
ExamineLeaveInterface hrProxy = (ExamineLeaveInterface) DynamicProxyInterceptor.bind(managerProxy,"com.daily.dutychain.HrExamineInterceptor");
hrProxy.examine(file); }
}

第七步:查看执行结果

 hr审核之前检查部门经理是否通过
部门经理审核之前检查是否通过员工主管审核
主管同意之前检查信息是否填写完整
员工张三的请假单审核完毕
审核完毕,主管签名
审核完毕,经理签名
审核完毕,hr签名

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

Java内功修炼系列一责任链模式的更多相关文章

  1. Java设计模式(14)责任链模式(Chain of Responsibility模式)

    Chain of Responsibility定义:Chain of Responsibility(CoR) 是用一系列类(classes)试图处理一个请求request,这些类之间是一个松散的耦合, ...

  2. java设计模式解析(11) Chain责任链模式

    设计模式系列文章 java设计模式解析(1) Observer观察者模式 java设计模式解析(2) Proxy代理模式 java设计模式解析(3) Factory工厂模式 java设计模式解析(4) ...

  3. Java设计模式系列之责任链模式

    责任链模式 责任链模式是一种对象的行为模式.在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并不知道 ...

  4. 浅谈Java五大设计原则之责任链模式

    首先我们得先定义一个责任链模式: 责任链模式是一种线性执行流程,多个对象都有机会去执行同一个任务,只是在执行过程中, 由于执行的权利和范围不一样,那么当自己不能处理此任务时,就必须将这个任务抛给下一个 ...

  5. Java进阶篇设计模式之八 ----- 责任链模式和命令模式

    前言 在上一篇中我们学习了结构型模式的享元模式和代理模式.本篇则来学习下行为型模式的两个模式, 责任链模式(Chain of Responsibility Pattern)和命令模式(Command ...

  6. Java描述设计模式(15):责任链模式

    本文源码:GitHub·点这里 || GitEE·点这里 一.生活场景描述 1.请假审批流程 公司常见的请假审批流程:请假天数 当 day<=3 天,项目经理审批 当 3<day<= ...

  7. Java设计模式(九)责任链模式 命令模式

    (十七)责任链模式 责任链模式的目的是通过给予多个对象处理请求的机会,已解除请求发送者与接受者之间的耦合关系.面对对象的开发力求对象之前保持松散耦合,确保对象各自的责任最小化.这种设计能够使得系统更加 ...

  8. Java内功修炼系列一代理模式

    代理模式是JAVA设计模式之一,网上设计模式相关的博文铺天盖地,参考它们有助于自己理解,但是所谓“尽信书不如无书”,在参考的同时也要思考其正确性,写博客也是为了记录自己理解知识点的思路历程和心路历程, ...

  9. Java内功修炼系列一工厂模式

    工厂模式是一种创建型模式,它提供了一种新的创建对象的方式,一般情况下我们都习惯用new关键字直接创建对象.有时候会遇到这种情况,我们需要根据具体的场景选择创建什么类型的对象,可能有多种类型都能选择,但 ...

随机推荐

  1. 微信小程序——单选项

    对于小程序单选,官方文档已经贴出了代码,我这里也不做过多解释,只是分享给大家一个小功能 一般在单选或者多选时,都会出现“其他”这个选项,如果通过input焦点事件.失焦事件来控制,代码会很繁琐 这里可 ...

  2. 17.splash_case03

    # python执行lua脚本 import requests from urllib.parse import quote lua = ''' function main(splash) retur ...

  3. 解决VirtualBox下关于CentOS7网络配置问题

    描述:安装了centos7,发现无法ping通网络,根据一些网上的建议,进行了一些修改,修改配置文件(/etc/sysconfig/network-scripts/ifcfg-enq03 ),但并没有 ...

  4. [AHOI2014/JSOI2014]骑士游戏

    题目 思博贪心题写了一个半小时没救了,我也没看出这是一个\(spfa\)来啊 设\(dp_i\)表示彻底干掉第\(i\)只怪物的最小花费,一个非常显然的事情,就是对于\(k_i\)值最小的怪物满足\( ...

  5. Mybatis Resultmap 简化之超级父类

    我们在写 mybatis多表关联查询的时候 ,要配置  resultmap ,实在太麻烦.而这个超级父类 可以省去我们查询多表时的map public class SuperPojo extends ...

  6. SpringBoot之集成通用Mapper

    第一种: 1.引入POM坐标,需要同时引入通用mapper和jpa <dependency> <groupId>tk.mybatis</groupId> <a ...

  7. 转载别人的ftp,觉得目录结构不错,学习

    开发简单的FTP:1. 用户登陆2. 上传/下载文件3. 不同用户家目录不同4. 查看当前目录下文件5. 充分使用面向对象知识 REDMAE 1 用户登陆 2 3 1.查看用户目录文件 4 2.上传文 ...

  8. Jmeter 录制脚本【转】

    Jmeter 录制脚本[转] Jmeter中有2种方法可以录制脚本.  不过我个人非常不推荐录制脚本,录制的脚本混乱,需要再次加工才能使用. 像我这么精通HTTP协议的人. 一直都是使用Fiddler ...

  9. 0810NOIP模拟测试赛后总结

    明日之后将是什么. 悲哀, 还是希望? 60分我没脸了…… 所以T1好不容易想到了正解结果实现打挂w0了…… 贪心想的还是相当完美的. 不知道我咋想的开了1e6个栈然后dfs模拟结果MLE原地自爆…… ...

  10. axios请求头几种区别:application/x-www-form-urlencoded

    今天小伙伴问我们项目axios默认请求头是application/x-www-form-urlencoded;charset=UTF-8, 现在有个后端接口要求请求头方式为application/js ...