《设计模式》责任链模式
定义:
- 责任链模式将链中每一个节点都看成一个对象,并且将这些节点对象连成一条链,请求会沿着这条链进行传递,直到有对象处理它为止,这使得多个对象都有机会接收请求,避免了请求发送者和接收者之间的耦合。
- 属于行为型设计模式。
责任链模式的角色组成:
- Handler(抽象处理者):定义一个处理请求的抽象方法,并维护一个下一个处理节点对象的引用。
- ConcreteHandler(具体处理者):实现了抽象处理请求方法,并在处理之前进行判断是否有相应的处理权限,有则处理,没有则将请求转发后继者处理。
责任链模式的 UML 类图:
🎈情景案例:大家在公司上班难免遇到有事需要请假的情况,就我所在的公司来说,请假时间不超过3个工作日的,自己的直接领导(leader)可以直接审批,但是如果大于三个工作日不超过五个工作日的,则需要经理(CommonManager)进行审批了,而请假时间超过5个工作日的需要总经理(GeneralManager)进行审批了。其实,请假审批流程这样的场景就可以使用责任链模式模拟,提出的请假请求被一层层传递转发,直到最终的决策者。
抽象处理者 Manager:
public abstract class Manager {protected String name;protected Manager superior;public Manager(String name) {this.name = name;}public void setSuperior(Manager superior) {this.superior = superior;}public abstract void requestAbsence(int days);
}
具体处理者 Leader:
public class Leader extends Manager{public Leader(String name) {super(name);}@Overridepublic void requestAbsence(int days) {if (days <= 3) {System.out.println(String.format("请假%s天被批准,审核人为%s!", days, name));} else {if (superior != null) {System.out.println(String.format("请假%s天被批准,审核人为%s,还需上级领导审核!", days, name));superior.requestAbsence(days);}}}
}
具体处理者 CommonManager:
public class CommonManager extends Manager{public CommonManager(String name) {super(name);}@Overridepublic void requestAbsence(int days) {if (days > 3 && days <= 5) {System.out.println(String.format("请假%s天被批准,审核人为%s!", days, name));} else {if (superior != null) {System.out.println(String.format("请假%s天被批准,审核人为%s,还需上级领导审核!", days, name));superior.requestAbsence(days);}}}
}
具体处理者 GeneralManager:
public class GeneralManager extends Manager {public GeneralManager(String name) {super(name);}@Overridepublic void requestAbsence(int days) {if (days > 5) {System.out.println(String.format("请假%s天被批准,审核人为%s!", days, name));}}
}
客户端 Client:
public class Client {public static void main(String[] args) {Leader leader = new Leader("主管");CommonManager commonManager = new CommonManager("经理");GeneralManager generalManager = new GeneralManager("总经理");leader.setSuperior(commonManager);commonManager.setSuperior(generalManager);leader.requestAbsence(6);}
}
责任链模式的优点:
- 请求处理对象仅需维持一个指向其后继者的引用,而不需要维持它对所有的候选处理者的引用,这样的责任链可以简化对象的相互连接,降低耦合度。
- 链路结构灵活,可以通过改变链路结构动态地新增或删减责任。
- 易于扩展新的请求处理类(节点),符合开闭原则。
责任链模式的缺点:
- 责任链太长或者处理时间过长,会影响整体性能。
- 如果建链不当,可能会造成循环调用,将导致系统陷入死循环。
- 一个请求也可能因职责链没有被正确配置而得不到处理。
责任链模式的适用场景:
- 多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定。
- 在不明确指定接收者的情况下,向多个对象中的一个提交请求。
- 需要可以动态指定一组对象处理请求,客户端可以动态创建责任链来处理请求,还可以改变链中处理者之间的先后次序。
🎈责任链模式在JDK源码
javax.servlet
包中的应用
Servlet API
中提供了一个 Filter
(过滤器)接口,通过过滤器技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截,一般常用于实现 URL
级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
Servlet API 中的 Filter
源码如下:
public interface Filter {// 过滤器第一次初始化时执行,初始化配置参数,在doFilter()方法之前被调用default void init(FilterConfig filterConfig) throws ServletException {}// 在客户端请求及服务器端回复时都将被自动调用,服务器每次在调用web资源之前,都会先调用一下该方法void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;// 结束过滤器,doFilter()方法完成后被调用default void destroy() {}
}
Filter
相当于责任链模式中的抽象处理者 Handler
,它是由 doFilter()
方法的最后一个参数 FilterChain
实现一条责任链的,其源码如下:
public interface FilterChain {/*** 调用链中的下一个过滤器,如果是调用链中最后一个过滤器,将调用链中最后一个资源* @param request 将沿着链请求* @param response 将沿着链回复 */public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException;}
FilterChain
类中只定义了一个 doFilter()
方法上,J2EE 只定义了一个规范,具体处理逻辑是由使用者自己来实现,例如 Spring 框架中的实现 MockFilterChain
类:
public class MockFilterChain implements FilterChain {@Nullableprivate ServletRequest request;@Nullableprivate ServletResponse response;private final List<Filter> filters;@Nullableprivate Iterator<Filter> iterator;public MockFilterChain() {this.filters = Collections.emptyList();}public MockFilterChain(Servlet servlet) {this.filters = initFilterList(servlet);}public MockFilterChain(Servlet servlet, Filter... filters) {Assert.notNull(filters, "filters cannot be null");Assert.noNullElements(filters, "filters cannot contain null values");this.filters = initFilterList(servlet, filters);}private static List<Filter> initFilterList(Servlet servlet, Filter... filters) {Filter[] allFilters = (Filter[])ObjectUtils.addObjectToArray(filters, new MockFilterChain.ServletFilterProxy(servlet));return Arrays.asList(allFilters);}@Nullablepublic ServletRequest getRequest() {return this.request;}@Nullablepublic ServletResponse getResponse() {return this.response;}public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {Assert.notNull(request, "Request must not be null");Assert.notNull(response, "Response must not be null");Assert.state(this.request == null, "This FilterChain has already been called!");if (this.iterator == null) {this.iterator = this.filters.iterator();}if (this.iterator.hasNext()) {Filter nextFilter = (Filter)this.iterator.next();nextFilter.doFilter(request, response, this);}this.request = request;this.response = response;}public void reset() {this.request = null;this.response = null;this.iterator = null;}private static final class ServletFilterProxy implements Filter {private final Servlet delegateServlet;private ServletFilterProxy(Servlet servlet) {Assert.notNull(servlet, "servlet cannot be null");this.delegateServlet = servlet;}public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {this.delegateServlet.service(request, response);}public void init(FilterConfig filterConfig) throws ServletException {}public void destroy() {}public String toString() {return this.delegateServlet.toString();}}
}
MockFilterChain
类把链中的所有 Filter
都放到 List
中,然后在调用 doFilter()
方法时循环迭代List
,也就是说 List
中的 Filter
会按顺序执行。