Chain of Responsibility pattern
A definition of Dian
A plurality of object a chance to handle the request, thereby avoiding the coupling between the sender and receiver of the request . These objects together into a chain, and pass the request along the chain until an object handles it up . (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.)
Two Dian understand
Focus on the chain of responsibility pattern is to "chain", passes the request on the "chain", if the "node" on the "chain" is responsible for handling the request, to take responsibility, otherwise it will pass the request to the next "node" .
Because it is processed by the object on the chain of responsibility in charge of processing the request, the consumer only need to deal with a request to the chain of responsibility, without concern for the details of processing, so that the coupling between the sender and receiver of the request.
Wed and Examples
Tomcat in the realization FilterChain
1. FilterChain Interface
Filtered port link, i.e., the chain of responsibility object interface encapsulates processed Filter, interact with the client, the client only need to request it to handle, do not need to know the internal details.
There are two general maintenance process implemented for Filter objects inside a array is a linked list, the FilterChain using arrays, linked lists is the 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 Interface
Processed interfaces, the most important is doFilter (ServletRequest request, ServletResponse response, FilterChain chain) , wherein the object transfer FilterChain, for controlling whether to continue to the next recursive call Filter.
/ ** * * reference the javax.servlet.Filter * * @author TimFruit * @date 19-5-11 PM 6:08 * / public interface the Filter { public void the init (the FilterConfig FilterConfig); interface method of processing true // public void the doFilter (the ServletRequest Request, the ServletResponse Response, the FilterChain catena alberghiera); public void the destroy (); }
3. FilterConfig Interface
Filter configuration interface, which FilterChain Tomcat's implementation is registered FilterConfig, through the initial configuration corresponding to FilterConfig Filter, in line with the principles of Demeter (the principle of least knowledge)
/** * * 参考 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 * *
4. AppFilterChain achieved, where the reference is implemented inside tomcat
/ ** * @author TimFruit * @date 19-5-12 AM 8:54 * / public class AppFilterChain the implements the FilterChain { // [warning] Tomcat source is an array (AppFilterConfig []) // used herein for convenience, Therefore, using the arrayList Private List <AppFilterConfig> = appFilterConfigs new new the ArrayList <> (); // identification filter chain invoked 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(A ClassNotFoundException | IllegalAccessException | an InstantiationException is E) { the throw new new ServletException ( "Get Filter Error" , E); } filter.doFilter (Request, Response, the this ); } } / ** * reuse * / void Reuse () { POS = 0 ; } }
5. AppFilterConfig implemented, with reference to the realization 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 to achieve
/** * * @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; } // choose to assume responsibility, the append "A" responseStr responseStr + = "A" ; response.setResponse (responseStr); // [warning] here is to continue the call chain, is also You may choose not to continue to call the chain.doFilter (Request, Response); } @Override public void the destroy () { } }
7. Scene class
/** * @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()); } }
Test Results:
request: ABCD
after filter, response: A_B_CDA
Case complete code:
https://gitee.com/timfruit189/test-design-pattern
Learning materials
<Zen design pattern> Qinxiao Bo
Tomcat source code