• 学习设计模式


    责任链模式

    一丶定义

       使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止.(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源码

    人生没有彩排,每一天都是现场直播
  • 相关阅读:
    180322
    20180317
    C语言编译器
    PAT甲级_PAT Advanced Level 1002. A+B for Polynomials (25) C
    java中的装箱与拆箱
    PAT甲级_PAT Advanced Level 1002. A+B for Polynomials (25)
    Java(3)_Ideal 使用指南
    4.jmeter参数化实战
    1.jmeter搭建环境
    Python_异常机制及日志
  • 原文地址:https://www.cnblogs.com/timfruit/p/10847668.html
Copyright © 2020-2023  润新知