学习设计模式 - 责任链模式
责任链模式
一丶定义
使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止.(Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.)
二丶理解
责任链模式的重点在于"链"上, 将请求在"链"上传递,如果"链"上的"节点"是负责处理该请求,则承担责任,否则就将请求传递给下一"节点".
由于是由责任链上的处理对象负责处理请求,使用方只需要将请求交给责任链处理即可,无须关心处理细节,从而使得请求的发送者和接受者之间的耦合关系.
三丶举例
Tomcat中的FilterChain实现
1. FilterChain接口
过滤链接口, 即责任链对象接口, 封装了处理对象Filter, 与客户端交互, 客户端只需要将请求交给它处理即可,不需要知道内部细节.
一般有两种实现用于维护内部的处理对象Filter, 一种是数组, 一种是链表, FilterChain是使用数组, 而Pipeline则是使用链表.
/** * 参考 javax.servlet.FilterChain * * @author TimFruit * @date 19-5-11 下午6:08 */ public interface FilterChain { /** * Causes the next filter in the chain to be invoked, or if the calling * filter is the last filter in the chain, causes the resource at the end of * the chain to be invoked. * * @param request * the request to pass along the chain. * @param response * the response to pass along the chain. * */ public void doFilter(ServletRequest request, ServletResponse response); }
2. Filter接口
处理对象接口, 最主要是doFilter(ServletRequest request, ServletResponse response, FilterChain chain)方法, 其中传递FilterChain对象, 是用于控制是否继续递归调用下一个Filter.
/** * * 参考 javax.servlet.Filter * * @author TimFruit * @date 19-5-11 下午6:08 */ public interface Filter { public void init(FilterConfig filterConfig) ; // 真正处理的接口方法 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) ; public void destroy(); }
3. FilterConfig 接口
配置Filter的接口, 其中Tomcat的FilterChain实现是注册FilterConfig, 通过该FilterConfig来初始化配置对应的Filter, 符合迪米特原则(最少知识原则)
/** * * 参考 javax.servlet.FilterConfig * * @author TimFruit * @date 19-5-11 下午6:08 */ public interface FilterConfig { /** * Get the name of the filter. */ public String getFilterName(); /** * Returns a <code>String</code> containing the valve of the named * initialization parameter, or <code>null</code> if the parameter does not * exist. * * @param name * <code>String</code> specifying the name of the initialization * parameter * * @return <code>String</code> containing the valve of the initialization * parameter */ public String getInitParameter(String name); /** * Returns the names of the filter's initialization parameters as an * <code>Enumeration</code> of <code>String</code> objects, or an empty * <code>Enumeration</code> if the filter has no initialization parameters. * * @return <code>Enumeration</code> of <code>String</code> objects * containing the names of the filter's initialization parameters */ public Enumeration<String> getInitParameterNames(); }
4. AppFilterChain实现, 其中是参考tomcat内部的实现
/** * @author TimFruit * @date 19-5-12 上午8:54 */ public class AppFilterChain implements FilterChain { //[warning] tomcat源码中是数组形式(AppFilterConfig[]) //这里为方便使用,所以使用了arrayList private List<AppFilterConfig> appFilterConfigs=new ArrayList<>(); // 过滤器链调用的的标识 private int pos=0; public AppFilterChain() { } public void addAppFilterConfig(AppFilterConfig filterConfig){ appFilterConfigs.add(filterConfig); } @Override public void doFilter(ServletRequest request, ServletResponse response) { //do other ... internalDoFilter(request, response); } private void internalDoFilter(ServletRequest request, ServletResponse response){ if(pos<appFilterConfigs.size()) { AppFilterConfig appFilterConfig = appFilterConfigs.get(pos); pos++; Filter filter; try { filter = appFilterConfig.getFilter(); } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) { throw new ServletException("获取过滤器出错", e); } filter.doFilter(request, response, this); } } /** * 重新使用 */ void reuse(){ pos=0; } }
5. AppFilterConfig实现, 参考tomcat的实现
/** * @author TimFruit * @date 19-5-12 上午8:54 */ public class AppFilterConfig implements FilterConfig{ /** * 过滤器链名字 */ private String name; private Map<String,String> paramMap; /** * 过滤器的类名 */ private String filterClass; private volatile Filter filter; /** * Empty String collection to serve as the basis for empty enumerations. */ private static final List<String> emptyString = Collections.emptyList(); public AppFilterConfig(String name, String filterClass) { this.name = name; this.filterClass=filterClass; } public AppFilterConfig(String name,String filterClass, Map<String, String> paramMap) { this.name = name; this.filterClass=filterClass; this.paramMap = paramMap; } // --------------------------------------- filterConfig methods @Override public String getFilterName() { return this.name; } @Override public String getInitParameter(String name) { if(paramMap==null){ return null; } if(paramMap.containsKey(name)){ return paramMap.get(name); } return null; } @Override public Enumeration<String> getInitParameterNames() { if(paramMap==null){ return Collections.enumeration(emptyString); } return Collections.enumeration(paramMap.keySet()); } // --------------------------------------- Filter getFilter() throws ClassNotFoundException, IllegalAccessException, InstantiationException { if(filter==null){ synchronized (AppFilterConfig.class){ Class filterClazz=Class.forName(this.filterClass); Filter filter=(Filter) filterClazz.newInstance(); filter.init(this); this.filter=filter; } } return filter; } }
6. Filter实现
/** * * @author TimFruit * @date 19-5-12 上午10:15 */ public class AppendAFilter implements Filter { @Override public void init(FilterConfig filterConfig) { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { String responseStr=response.getResponse(); if(responseStr==null){ String requestStr=request.getRequest(); if(requestStr==null){ requestStr=""; } responseStr=requestStr; } //选择承担责任, append "A" responseStr=responseStr+"A"; response.setResponse(responseStr); //[warning] 这里是继续调用链, 也可以选择不继续调用 chain.doFilter(request, response); } @Override public void destroy() { } }
7. 场景类
/** * @author TimFruit * @date 19-5-12 上午10:48 */ public class Client { public static void main(String[] args) { AppFilterChain filterChain=new AppFilterChain(); AppFilterConfig appendAFilterConfig=new AppFilterConfig("appendAFilter", AppendAFilter.class.getName()); filterChain.addAppFilterConfig(appendAFilterConfig); // append "A" Map<String,String> BFilterMap=new HashMap<>(); BFilterMap.put(ReplaceBFilter.REPLACE_STR, "_B_"); //将"B"替换成"_B_" AppFilterConfig replaceBFilterConfig=new AppFilterConfig("replaceBFilter", ReplaceBFilter.class.getName(), BFilterMap); filterChain.addAppFilterConfig(replaceBFilterConfig); ServletRequest request=new SimpleRequest("ABCD"); ServletResponse response=new SimpleResponse(); System.out.println("request: "+request.getRequest()); filterChain.doFilter(request, response); System.out.println("after filter, response: "+response.getResponse()); } }
测试结果:
request: ABCD
after filter, response: A_B_CDA
完整代码案例:
https://gitee.com/timfruit189/test-design-pattern
学习资料
<设计模式之禅> 秦小波
Tomcat源码