本文内容思惟导图以下:java
责任链模式定义:为请求建立一个处理此请求对象的链。json
适用场景(核心):只要把你的请求抛给第一个处理者,不用关心谁处理的,而且最终会返回你一个结果。设计模式
优势:请求者和处理者解耦,请求者不用知道谁处理的,处理者能够不用知道请求的全貌。数组
缺点:每一个请求从链头遍历到链尾,影响性能。代码调试时候不方便。app
类型:行为型。ide
类图:性能
源码中的典型应用:测试
员工在OA系统中提交请假申请,首先项目经理处理,他能审批3天之内的假期,若是大于3天,则由项目经理则转交给总经理处理。接下来咱们用责任链模式实现这个过程。this
一、封装请假信息实体类spa
public class LeaveRequest { private String name; // 请假人姓名 private int numOfDays; // 请假天数 private int workingAge; //员工工龄(在公司大于2年则总经理会审批) //省略get..set.. }
二、抽象处理者类 Handler,维护一个nextHandler属性,该属性为当前处理者的下一个处理者的引用;声明了抽象方法process,其实在这里也用了方法模板模式:
public abstract class ApproveHandler { protected ApproveHandler nextHandler;//下一个处理者(与类一致,这段代码很重要) public void setNextHandler(ApproveHandler approveHandler){ this.nextHandler=approveHandler; } public abstract void process(LeaveRequest leaveRequest); // 处理请假(这里用了模板方法模式) }
三、项目经理处理者,能处理小于3天的假期,而请假信息里没有名字时,审批不经过:
public class PMHandler extends ApproveHandler{ @Override public void process(LeaveRequest leaveRequest) { //未填写姓名的请假单不经过 if(null != leaveRequest.getName()){ if(leaveRequest.getNumOfDays() <= 3){ System.out.println(leaveRequest.getName()+",你经过项目经理审批!"); }else { System.out.println("项目经理转交总经理"); if(null != nextHandler){ nextHandler.process(leaveRequest); } } }else { System.out.println("请假单未填写完整,未经过项目经理审批!"); return; } } }
四、总经理处理者,能处理大于3天的假期,且工龄超过2年才会审批经过:
public class GMHandler extends ApproveHandler{ @Override public void process(LeaveRequest leaveRequest) { //员工在公司工龄超过2年,则审批经过 if(leaveRequest.getWorkingAge() >=2 && leaveRequest.getNumOfDays() > 3){ System.out.println(leaveRequest.getName()+",你经过总经理审批!"); if(null != nextHandler){ nextHandler.process(leaveRequest); } }else { System.out.println("在公司年限不够,长假未经过总经理审批!"); return; } } }
实例代码完成,咱们测试一下:
public class Test { public static void main(String[] args) { PMHandler pm = new PMHandler(); GMHandler gm = new GMHandler(); LeaveRequest leaveRequest = new LeaveRequest(); leaveRequest.setName("张三"); leaveRequest.setNumOfDays(4);//请假4天 leaveRequest.setWorkingAge(3);//工龄3年 pm.setNextHandler(gm);//设置传递顺序 pm.process(leaveRequest); } }
运行结果:
------
项目经理转交总经理
张三,你经过总经理审批!
------
Filter接口有很是多的实现类,这里挑选doFilter方法中的FilterChain参数来看,Tomcat和SpringSecurity中都用到责任链模式:
进入第一个,过滤器链 ApplicationFilterChain 的关键代码以下,过滤器链实际是一个 ApplicationFilterConfig 数组:
final class ApplicationFilterChain implements FilterChain, CometFilterChain { private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0]; // 过滤器链 private Servlet servlet = null; // 目标 // ... @Override public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { if( Globals.IS_SECURITY_ENABLED ) { // ... } else { internalDoFilter(request,response); // 调用 internalDoFilter 方法 } } private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { // Call the next filter if there is one if (pos < n) { // 从过滤器数组中取出当前过滤器配置,而后下标自增1 ApplicationFilterConfig filterConfig = filters[pos++]; Filter filter = null; try { filter = filterConfig.getFilter(); // 从过滤器配置中取出该 过滤器对象 if( Globals.IS_SECURITY_ENABLED ) { final ServletRequest req = request; final ServletResponse res = response; Principal principal = ((HttpServletRequest) req).getUserPrincipal(); Object[] args = new Object[]{req, res, this}; SecurityUtil.doAsPrivilege("doFilter", filter, classType, args, principal); } else { // 调用过滤器的 doFilter,完成一个过滤器的过滤功能 filter.doFilter(request, response, this); } return; // 这里很重要,不会重复执行后面的 servlet.service(request, response) } // 执行完过滤器链的全部过滤器以后,调用 Servlet 的 service 完成请求的处理 if ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse)) { if( Globals.IS_SECURITY_ENABLED ) { } else { servlet.service(request, response); } } else { servlet.service(request, response); } } // 省略... }
这里能够看出ApplicationFilterChain类扮演了抽象处理者角色,doFilter就相似于刚才请假流程里的process方法。
当下标小于过滤器数组长度 n 时,也就是过滤器链未执行完,从数组中取出并调用当前过滤器的 doFilter方法 ,若是下标一直小于n,则循环调用doFilter方法经过嵌套递归的方式来串成一条链。
当最后的过滤器执行完毕,也就是走到最后一个return;时,结束递归调用doFilter。if (pos < n) 为false,调用后面的servlet.service(request, response) 方法。return;这一点在请假流程里也有体现。
参考: