從Filter看責任鏈模式
阿新 • • 發佈:2019-01-06
模擬請求
一個Request類來模擬請求物件、一個Response類來模擬響應物件、一個APP類用來模擬請求處理的過程,可以認為是Servlet請求處理的一個簡版
package com.seven.filter;
public class Request {
/**
* 請求資料
*/
private String data;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
package com.seven.filter;
public class Response {
/**
* 響應資料
*/
private String data;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
package com.seven.filter;
public class App {
public static void main(String[] args) {
Request request = new Request();
Response response = process(request);
System.out.println(response.getData());
}
/**
* 模擬請求處理全過程
*
* @param request 請求物件【模擬HttpServletRequest物件】
* @return Response 返回物件【模擬HttpServletResponse物件】
*/
private static Response process(Request request) {
Response response = new Response();
response.setData("處理成功");
return response;
}
}
新增功能
- 新增引數校驗,判斷請求引數中是否包含test字串,不包含的話直接處理失敗
package com.seven.filter;
public class App {
public static void main(String[] args) {
Request request = new Request();
Response response = process(request);
System.out.println(response.getData());
}
/**
* 模擬請求處理全過程
*
* @param request 請求物件【模擬HttpServletRequest物件】
* @return Response 返回物件【模擬HttpServletResponse物件】
*/
private static Response process(Request request) {
Response response = new Response();
if (request != null && request.getData() != null && request.getData().contains("test")) {
response.setData("處理成功");
}
response.setData("處理失敗");
return response;
}
}
- 新增日誌功能,在請求處理前後新增日誌
package com.seven.filter;
public class App {
public static void main(String[] args) {
Request request = new Request();
Response response = process(request);
}
/**
* 模擬請求處理全過程
*
* @param request 請求物件【模擬HttpServletRequest物件】
* @return Response 返回物件【模擬HttpServletResponse物件】
*/
private static Response process(Request request) {
Response response = new Response();
if (request != null && request.getData() != null && request.getData().contains("test")) {
System.out.println("————————開始處理——————————");//模擬日誌
response.setData("處理成功");
System.out.println("————————處理結束——————————");//模擬日誌
}
response.setData("處理失敗");
return response;
}
}
缺點
- 每次新加功能需要改動主方法,違反開閉原則,不易擴充套件
- 新增的引數校驗、日誌都不是主要業務邏輯,而卻和主要業務程式碼耦合在一起,經常改動,風險較大
Filter 模式
先回憶下我們使用Filter的情況,Filter是針對請求的,一般是在請求處理前進行攔截,做一些比如統一編碼、許可權校驗、日誌記錄等功能,我們下面就模擬許可權校驗(這裡用引數檢驗代替)、日誌記錄這兩項功能,使用Filter模式來模擬上面的功能實現,同時根據FilterChain,我們體會下責任鏈模式
package com.seven.filter;
public interface Filter {
/**
* 過濾器
* @param request 請求物件
* @param response 返回物件
*/
void doFilter(Request request, Response response,FilterChain chain);
}
package com.seven.filter;
/**
* 引數校驗過濾器
*/
public class ParameterValidateFilter implements Filter {
@Override
public void doFilter(Request request, Response response,FilterChain chain) {
if (request != null && request.getData() != null && request.getData().contains("test")) {
chain.doFilter(request,response,chain);
}else {
response.setData("處理失敗");
}
}
}
package com.seven.filter;
/**
* 日誌過濾器
*/
public class LogFilter implements Filter {
@Override
public void doFilter(Request request, Response response, FilterChain chain) {
System.out.println("————————開始處理——————————");//模擬日誌
chain.doFilter(request, response, chain);
System.out.println("————————處理結束——————————");//模擬日誌
}
}
package com.seven.filter;
import java.util.ArrayList;
import java.util.List;
/**
* 過濾器鏈【執行責任鏈模式的主要成員】
*/
public class FilterChain implements Filter{
/**
* 過濾器列表
*/
private List<Filter> filters = new ArrayList<>();
private int index=0;
/**
* 新增過濾器
* @param filter
*/
public void addFilter(Filter filter) {
filters.add(filter);
}
@Override
public void doFilter(Request request, Response response,FilterChain chain) {
if(index==filters.size()){
/**
* 真正處理請求
*/
response.setData("處理成功");
return;
}
Filter filter = filters.get(index);
index++;
filter.doFilter(request,response,chain);
}
}
package com.seven.filter;
public class App {
public static void main(String[] args) {
Request request = new Request();
request.setData("test");
process(request);
}
/**
* 模擬請求處理全過程
*
* @param request 請求物件【模擬HttpServletRequest物件】
* @return Response 返回物件【模擬HttpServletResponse物件】
*/
private static Response process(Request request) {
Response response = new Response();
FilterChain chain = new FilterChain();
chain.addFilter(new ParameterValidateFilter());
chain.addFilter(new LogFilter());
chain.doFilter(request, response, chain);
return response;
}
}
————————開始處理——————————
處理成功
————————處理結束——————————
總結
- Filter是針對請求進行攔截、意在請求前進行一些過濾、許可權校驗、日誌記錄、統一編碼等
- 所有Filter統一在FilterChain中組成一個鏈條,然後呼叫也統一由FilterChain來協調,確保以鏈條的模式執行
- 責任鏈模式是一種重要的設計模式,如Servlet中的Filter模式、Mybatis中的Plugin模式等都是責任鏈模式的體現
微信公眾號:宋坤明
下面的是我的公眾號二維碼圖片,歡迎關注。