本文將從簡單的場景引入, 逐步優化, 最後給出具體的責任鏈設計模式實現.html
public class Demo1 {
public static void main(String[] args) {
String msg = "你們好 :), <script>haha</script> 我要說超級敏感的話";//假設有一條這樣的貼子
MsgProcessor mp = new MsgProcessor();
mp.setMsg(msg);//處理帖子
System.out.println(mp.process());
}
}
//帖子處理器
class MsgProcessor{
private String msg;
public String process(){
//對html標籤<>進行處理
String str = msg.replace("<", "[").replace(">", "]");
//對敏感字符盡心處理
str = str.replace("敏感", "正常");
//對錯誤的表情格式進行處理
str = str.replace(":)", "^_^");
return str;
}
//get() / set() 方法...
}
//輸出結果
你們好 ^_^, [script]haha[/script] 我要說超級正常的話
複製代碼
public class Demo2 {
public static void main(String[] args) {
String msg = "你們好 :), <script>haha</script> 我要說超級敏感的話";
MsgProcessor mp = new MsgProcessor();
mp.setMsg(msg);
System.out.println(mp.process());
}
}
class MsgProcessor{
private String msg;
private Filter[] filters = {new HtmlFilter(), new SensitiveFilter(), new ExpressionFilter()};
public String process(){
for(Filter f : filters){
msg = f.doFilter(msg);
}
return msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
//過濾器接口
interface Filter{
public String doFilter(String s);
}
//處理html標籤
class HtmlFilter implements Filter{
@Override
public String doFilter(String s) {
return s.replace("<", "[").replace(">", "]");
}
}
//處理敏感詞句
class SensitiveFilter implements Filter{
@Override
public String doFilter(String s) {
return s.replace("敏感", "正常");
}
}
//處理表情
class ExpressionFilter implements Filter{
@Override
public String doFilter(String s) {
return s.replace(":)", "^_^");
}
}
複製代碼
Filter
接口, 那麼就能夠在一條過濾鏈中任意加入其餘過濾器和過濾鏈了.FilterChain
, 用過濾鏈替代原來的MsgProcessor
.public class Demo3 {
public static void main(String[] args) {
String msg = "你們好 :), <script>haha</script> 我要說超級敏感的話";//待處理的帖子
FilterChain fc1 = new FilterChain();//建立一條過濾器鏈1
fc1.add(new HtmlFilter())
.add(new SensitiveFilter());//往過濾器鏈1中添加過濾器
FilterChain fc2 = new FilterChain();//建立一條過濾器鏈2
fc2.add(new ExpressionFilter());//往過濾器鏈2中添加過濾器
fc1.add(fc2);//把過濾器鏈2看成過濾器添加到過濾器鏈1中,(過濾器鏈實現了Filter接口)
msg = fc1.doFilter(msg);//使用過濾器鏈1對帖子進行過濾
System.out.println(msg);
}
}
class FilterChain implements Filter{
private List<Filter> list = new ArrayList<>();
public FilterChain add(Filter filter){
this.list.add(filter);
return this;
}
@Override
public String doFilter(String s) {
for(Filter f : list){
s = f.doFilter(s);
}
return s;
}
}
class HtmlFilter implements Filter{
@Override
public String doFilter(String s) {
return s.replace("<", "[").replace(">", "]");
}
}
class SensitiveFilter implements Filter{
@Override
public String doFilter(String s) {
return s.replace("敏感", "正常");
}
}
class ExpressionFilter implements Filter{
@Override
public String doFilter(String s) {
return s.replace(":)", "^_^");
}
}
interface Filter{
public String doFilter(String s);
}
複製代碼
index
序號, 經過序號控制執行順序. 至於後面對response
的倒序請求, 則經過方法返回實現. 這部分設計純用文字難以講清, 請務必看下面的代碼和代碼後的分析, 配圖.public class Demo4 {
public static void main(String[] args) {
String msg = "你們好 :), <script>haha</script> 我要說超級敏感的話";//如下三行模擬一個請求
Request request = new Request();
request.setRequestStr(msg);
Response response = new Response();//響應
FilterChain fc = new FilterChain();//過濾器鏈
HtmlFilter f1 = new HtmlFilter();//建立過濾器
SensitiveFilter f2 = new SensitiveFilter();
ExpressionFilter f3 = new ExpressionFilter();
fc.add(f1);//把過濾器添加到過濾器鏈中
fc.add(f2);
fc.add(f3);
fc.doFilter(request, response, fc);//直接調用過濾器鏈的doFilter()方法進行處理
System.out.println(request.getRequestStr());
}
}
interface Filter{
public void doFilter(Request request, Response response, FilterChain fc);
}
class FilterChain implements Filter{
private List<Filter> list = new ArrayList<>();
private int index = 0;
public FilterChain add(Filter filter){
this.list.add(filter);
return this;
}
@Override
public void doFilter(Request request, Response response, FilterChain fc) {
if(index == list.size()){
return;//這裏是逆序處理響應的關鍵, 當index爲容器大小時, 證實對request的處理已經完成, 下面進入對response的處理.
}
Filter f = list.get(index);//過濾器鏈按index的順序拿到filter
index++;
f.doFilter(request, response, fc);
}
}
class HtmlFilter implements Filter{
@Override
public void doFilter(Request request, Response response, FilterChain fc) {
request.setRequestStr(request.getRequestStr().replace("<", "[").replace(">","]"));
System.out.println("在HtmlFilter中處理request");//先處理request
fc.doFilter(request, response, fc);//調用過濾器鏈的doFilter方法, 讓它去執行下一個Filter的doFilter方法, 處理response的代碼將被掛起
System.out.println("在HtmlFilter中處理response");
}
}
class SensitiveFilter implements Filter{
@Override
public void doFilter(Request request, Response response, FilterChain fc) {
request.setRequestStr(request.getRequestStr().replace("敏感", "正常"));
System.out.println("在SensitiveFilter中處理request");
fc.doFilter(request, response, fc);
System.out.println("在SensitiveFilter中處理response");
}
}
class ExpressionFilter implements Filter{
@Override
public void doFilter(Request request, Response response, FilterChain fc) {
request.setRequestStr(request.getRequestStr().replace(":)", "^_^"));
System.out.println("在ExpressionFilter中處理request");
fc.doFilter(request, response, fc);
System.out.println("在ExpressionFilter中處理response");
}
}
class Request{
private String requestStr;//真正的Request對象中是包含不少信息的, 這裏僅用一個字符串做模擬
public String getRequestStr() {
return requestStr;
}
public void setRequestStr(String requestStr) {
this.requestStr = requestStr;
}
}
class Response{
private String responseStr;
public String getResponseStr() {
return responseStr;
}
public void setResponseStr(String responseStr) {
this.responseStr = responseStr;
}
}
複製代碼
Request
和Response
對象. Request
在傳入進後端時須要依次被過濾器1, 2, 3進行處理, Response
對象在輸出時要依次被過濾器3, 2, 1處理.doFilter()
方法對request對象進行處理index
值爲0, 經過index
咱們找到第一個過濾器並調用它的doFilter()
方法, 咱們觀察這段代碼class HtmlFilter implements Filter{
@Override
public void doFilter(Request request, Response response, FilterChain fc) {
request.setRequestStr(request.getRequestStr().replace("<", "[").replace(">","]"));
System.out.println("在HtmlFilter中處理request");//先處理request
fc.doFilter(request, response, fc);//調用過濾器鏈的doFilter方法, 讓它去執行下一個Filter的doFilter方法, 處理response的代碼將被掛起
//在返回的過程當中執行response
System.out.println("在HtmlFilter中處理response");
}
}
複製代碼
doFilter()
方法後, 首先會對request
請求進行處理, 而後又調用了過濾器鏈的doFilter()
方法. 這就是整個責任鏈模式的精妙之處, 它解釋了爲何要給doFilter()
加上一個過濾器鏈參數, 就是爲了讓每一個過濾器能夠調用過濾器鏈自己執行下一個過濾器.doFilter
方法執行, 這時index
爲1, 也就是拿到第二個過濾器, 而後繼續處理.response
的處理暫時沒法執行, 它必須等待上面的對過濾器鏈的方法返回才能被執行.response
響應被過濾器3, 2, 1(和請求倒序)執行.
public interface Filter {
void init(FilterConfig var1) throws ServletException;
//熟悉的doFilter(), 熟悉的3個參數request, reponse, filterChain.
void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
void destroy();
}
複製代碼
Filter
接口的定義和咱們的講解的差很少, 只是多了初始化和銷燬的方法.public interface FilterChain {
void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}
複製代碼
FilterChain
也向上抽取成接口, 不過這裏的FilterChain
沒有實現Filter
接口, 也就是說咱們不能把兩條FilterChain
拼接在一塊兒, 換個角度想Tomcat中的過濾器的可擴展性尚未咱們例子中的好呢^_^