天天看點

設計模式-責任鍊模式

了解

設計模式-責任鍊模式

責任鍊的執行序列是一環連着一環,後一環的執行依賴前一環的執行,層層遞進.

設計模式-責任鍊模式

流程圖

設計模式-責任鍊模式
設計模式-責任鍊模式
設計模式-責任鍊模式

組成部分

  1. 鍊條:負責承前啟後;
  2. 鍊條上的環:執行業務邏輯,決定是否繼續執行下一個環(有的情況由鍊條決定);
  3. 執行流:
  4. 前期:由外層到裡層;
  5. 後期:由裡層到外層

特點

  1. 鍊條上相鄰的環之間會影響,影響入參和出參;
  2. 每個環負責相對獨立的任務,比如有的負責字元編碼設定,有的負責流的編碼和解碼(比如gzip),有的負責記錄日志等

執行個體

一個簡單的 demo

設計模式-責任鍊模式

項目代碼

設計模式-責任鍊模式

鍊條類

public class DaoFilterChain {
    private List<IFilter> filterList = new ArrayList<>();
    private int index = 0;
    private boolean hasAddDefaultFilter = false;

    public DaoFilterChain addFilter(IFilter filter) {
        if (hasAddDefaultFilter) {
            throw new RuntimeException("自定義過濾器必須在預設過濾器之前添加");
        }
        this.filterList.add(filter);
        return this;
    }

    /***
     * 專門添加最基礎的DaoFilter
     * @param filter
     * @return
     */
    public DaoFilterChain addDefaultFilter(IFilter filter) {
        this.filterList.add(filter);
        hasAddDefaultFilter = true;
        return this;
    }

    public void reset() {
        this.index = 0;
    }

    private IFilter next() {
        if (index == filterList.size()) {
            return null;
        }
        IFilter filter = filterList.get(index);
        index++;
        return filter;

    }


    public void doFilter(DaoRequest request, DaoResponse response) {
        IFilter filter = next();
        if (null == filter) {
            System.out.println("結束 index :" + index);
            return;
        }
        filter.doFilter(request, response, this);
    }


}           

過濾器接口

public interface IFilter {
    /***
     * 最後一個過濾器一定是DefaultDaoFilter
     * @param request
     * @param response
     * @param filterChain
     */
    void doFilter(DaoRequest request, DaoResponse response, DaoFilterChain filterChain);
}           

javax.servlet.Filter

過濾器核心方法 :

public void doFilter(ServletRequest request, ServletResponse response,
                     FilterChain chain)
        throws IOException, ServletException;           

鍊條:org.apache.catalina.core.ApplicationFilterChain

源碼見:

http://www.docjar.com/html/api/org/apache/catalina/core/ApplicationFilterChain.java.html
設計模式-責任鍊模式

doFilter 核心代碼 (去掉了其他代碼):

ApplicationFilterConfig filterConfig = filters[pos++];
     Filter filter = null;
     filter = filterConfig.getFilter();
     filter.doFilter(request, response, this);           

過濾器執行個體 :支援跨域

設計模式-責任鍊模式

其他過濾器執行個體

設計模式-責任鍊模式

租戶攔截器

設計模式-責任鍊模式

接口:

public interface IRequestFilter {
    void doFilter(HttpFormContentRequestWrapper request, HttpServletResponse response, RequestFilterChain filterChain) throws IOException, ServletException;
}           
設計模式-責任鍊模式

鍊條類 RequestFilterChain

public class RequestFilterChain {
    private List<IRequestFilter> filterList = new ArrayList<>();
    private final static Logger logger = LoggerFactory.getLogger(RequestFilterChain.class);
    private ThreadLocal<Integer> indexLocal = new ThreadLocal<Integer>() {
        @Override
        protected Integer initialValue() {
            return 0;
        }
    };
    private ThreadLocal<Boolean> hasAddDefaultFilter = new ThreadLocal<Boolean>() {
        @Override
        protected Boolean initialValue() {
            return Boolean.FALSE;
        }
    };

    public RequestFilterChain addFilter(IRequestFilter filter) {
        if (hasAddDefaultFilter.get()) {
            throw new RuntimeException("自定義過濾器必須在預設過濾器之前添加");
        }
        this.filterList.add(filter);
        return this;
    }

    public RequestFilterChain removeFilter(IRequestFilter filter) {
        this.filterList.remove(filter);
        return this;
    }

    public RequestFilterChain addDefaultFilter(IRequestFilter filter) {
        this.filterList.add(filter);
        hasAddDefaultFilter.set(true);
//        DefaultFormRequestWrapperFilter defaultDaoFilter = (DefaultFormRequestWrapperFilter) filter;
        return this;
    }

    public void reset() {
        indexLocal.set(0);
    }

    private IRequestFilter next() {
        if (indexLocal.get() == filterList.size()) {
            return null;
        }
        IRequestFilter filter = filterList.get(indexLocal.get());
//        index++;
        indexLocal.set(indexLocal.get() + 1);
        return filter;

    }

    public void doFilter(HttpFormContentRequestWrapper request, HttpServletResponse response) throws IOException, ServletException {
        IRequestFilter filter = next();
        if (null == filter) {
            return;
        }
        try {
            filter.doFilter(request, response, this);
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

}           

MultipleTenantsFilter 做了什麼

設計模式-責任鍊模式

适用場景

  1. 同時有請求和應答的場景,例如HTTP請求,資料庫查詢;
  2. 映射層轉化
  3. 需要決定是否中斷流程的執行;
  4. 業務的執行分為多個中間環節,中間環節的個數可以定制;

和aop的差別

aop展現的是代理模式,實際是動态代理或 cglib

感想

  1. 責任鍊模式,依然符合開閉原則,比如由于業務的發展,需要添加新的邏輯,那麼就可以增加一個過濾器,而不用修改原來的邏輯處理;
  2. 對于邏輯比較複雜,且容易變動的邏輯,可以充分使用責任鍊模式,把相對聚合的邏輯抽取出來,作為一個個環,後面增加新的邏輯隻需要增加新的環即可,也可以根據實際需求修改鍊條上環的順序。