責任鏈就是通過一連串的過濾器(filter)來對信息進行處理:
1.最簡單的實現方案,通過filter數組來實現。
filter接口,用來統一方法名。
package com.bjsxt.dp.filter;
//定義一個接口,用來指定方法的名字爲doFilter
publicinterface Filter {
String doFilter(String str);
}
FacFilter實現Filter接口
package com.bjsxt.dp.filter;
publicclass FaceFilter implements Filter {
//@Override
//把:)替換成爲^V^
public String doFilter(String str) {
return str.replace(":)", "^V^");
}
}
HTMLFilter實現Filter接口
package com.bjsxt.dp.filter;
publicclass HTMLFilter implements Filter {
//@Override
//把<替換成爲[, 把>替換成]
public String doFilter(String str) {
//process the html tag<>
String r = str.replace('<', '[')
.replace('>', ']');
return r;
}
}
SesitiveFilter實現Filter接口
package com.bjsxt.dp.filter;
publicclass SesitiveFilter implements Filter {
//@Override
//把“被就業" 替換成爲"就業"
//把“敏感" 替換爲“”
public String doFilter(String str) {
//process the sensitive words
String r = str.replace("被就業", "就業")
.replace("敏感", "");
return r;
}
}
如果不使用責任鏈,可以在使用者,當中使用一個filter的數組來保存每個filter,並且分別調用每個filter的doFilter方法。
專門的字符串處理類:
package com.bjsxt.dp.filter;
publicclass MsgProcessor1 {
private String msg;
//filter數組
Filter[] filters = {new HTMLFilter(), new SesitiveFilter(), new FaceFilter()};
public String getMsg() {
returnmsg;
}
publicvoid setMsg(String msg) {
this.msg = msg;
}
public String process() {
String r = msg;
//對字符串r,調用所有的filter
for (Filter f: filters) {
r = f.doFilter(r);
}
return r;
}
}
使用者就只需要給定字符串:
package com.bjsxt.dp.filter;
publicclass Main1 {
/**
*@paramargs
*/
publicstaticvoid main(String[] args) {
//對應一條信息當中各種信息進行替換
Stringmsg = "大家好:),<script>,敏感,被就業,網絡授課沒感覺,因爲看不見大家夥兒";
MsgProcessor mp = new MsgProcessor();
mp.setMsg(msg);
Stringresult = mp.process();
System.out.println(result);
}
}
爲了實現能靈活的在當前鏈當中打開一個缺口,加入新的過濾器(鏈),就提供了責任鏈這樣一種方式。
2.通過責任鏈模式
責任鏈的主要任務是能夠靈活的設定(添加和刪除)過濾器的順序和組合。
可以有多個責任鏈。
責任鏈本身也是一個過濾器,一個大過濾器,裏面包含了很多小過濾器。
Main是使用者。也就是用戶,不需要知道細節的實現。
package com.bjsxt.dp.filter;
publicclass Main {
/**
*@paramargs
*/
publicstaticvoid main(String[] args) {
//對應一條信息當中各種信息進行替換
String msg = "大家好:),<script>,敏感,被就業,網絡授課沒感覺,因爲看不見大家夥兒";
MsgProcessor mp = new MsgProcessor();
mp.setMsg(msg);
FilterChain fc = new FilterChain();
//鏈條式編程,可以反覆添加多個filter
fc.addFilter(new HTMLFilter())
.addFilter(new SesitiveFilter())
;
//把facefilter添加到fc2當中,那麼就有兩個fc:fc1和fc2
FilterChain fc2 = new FilterChain();
fc2.addFilter(new FaceFilter());
//因爲fc2也實現了filter接口,那麼fc2本身也就是一個filter,所以可以被添加到fc當中。
//所以fc2可以靈活的添加到fc當中的任何位置,由使用者,也就是main來控制。
fc.addFilter(fc2);
mp.setFc(fc);
String result = mp.process();
System.out.println(result);
}
}
MsgProcessor是用來處理消息的,提供了一個porcess()方法。在MsgProcessor當中有一個FilterChain對象。其實這個類可有可沒有。也可以把這個類整合到main裏面去。
package com.bjsxt.dp.filter;
publicclass MsgProcessor {
private String msg;
//把filterchain作爲一個成員變量放到這邊,過濾規則都是有FC來實現。
FilterChain fc;
public FilterChain getFc() {
returnfc;
}
publicvoid setFc(FilterChain fc) {
this.fc = fc;
}
public String getMsg() {
returnmsg;
}
publicvoid setMsg(String msg) {
this.msg = msg;
}
//其實調用的是filterChain的doFilter方法,還是把每個Filter拿出來,每個執行一遍doFilter方法。
//現在其實process自己什麼都不做,都是FC來處理。
public String process() {
returnfc.doFilter(msg);
}
}
FilterChain當中可以添加和刪除filter。本例中只實現了添加,沒實現刪除。要注意的是,這些filter需要根據使用者的需求(選擇哪些filter,filter的順序),在main裏面由使用者來添加的。FilterChain應該是一個很靈活的類。最關鍵的一步,是它自己也實現了filter接口。從來能夠被添加到另一個FilterChain對象當中去,成爲別人的一部分。
package com.bjsxt.dp.filter;
import java.util.ArrayList;
import java.util.List;
//filterChain自己也實現了filter接口,也就是說,
//filterChain自己也可以作爲一個filter對象,被添加到另外一個Filterchain當中去.
//這樣就實現了靈活的添加。哪怕是把一根filterChain作爲一個大的fitler添加
//到另外一個fitlerChian當中。
publicclass FilterChain implements Filter {
//在filterChain當中加入一個arraylist來存放filter
List<Filter> filters = new ArrayList<Filter>();
//把fitler加入到arraylist當中
//注意這裏有個技巧,就是把這個方法的返回值設定爲這個類自身。那麼返回的還是這個類,又可以調用add方法。
//那麼在使用這個類的時候,就可以用 fc.addFilter(new HTMLFilter()).addFilter(newSesitiveFilter());
//這樣的方法來在使用者添加對象。這種方法叫鏈條式編程。
public FilterChain addFilter(Filter f) {
this.filters.add(f);
returnthis;
}
//把原MsgProcessor的處理字符串的方法,放到這裏來了,那麼FC就是專門用來處理字符串。
//MsgProcessor和業務邏輯分開。
public String doFilter(String str) {
String r = str;
for(Filter f: filters) {
r = f.doFilter(r);
}
return r;
}
}
3.雙向責任鏈模式(主要是順序的控制,個人感覺是遞歸思想的應用,當然這裏不完全是遞歸。)
要求:過濾的信息,從客戶端上到服務器端需要通過1,2,3這樣的過濾,而從服務器到客戶端的過濾順序是3,2,1.雙向過濾。而我們已經實現了,從客戶端上到服務器端的單項過濾。其實質是一個堆棧結構,是先進後出的順序。
問題實現的關鍵是在服務器向客戶端返回的時候,需要是3,2,1的順序。
如果要在服務器到客戶端的過濾順序也實現1,2,3非常的簡單,只需要在從客戶端上到服務器端調用責任鏈的時候,也調用對response的處理就可以。那麼現在需要反向調用,實現的邏輯就比較複雜。
首先是filter接口,注意現在的方法定義當中的參數。
package com.bjsxt.dp.filter;
//現在的參數,就是request,response,還有chain
//傳遞的時候,可以是request+空的response
//或者是response+空的request
//注意現在的返回值,不再是string類型,而是把處理完成的信息保存在request和response對象當中。
//所以返回值爲void。
publicinterface Filter {
//FilterChain在這裏的意義: filter在FC裏面,如果給定chain,
//當調用doFilter的時候,就可以指定下一步的FC怎麼走
//靈活,可以實現反向。
void doFilter(Request request, Response response, FilterChainchain);
}
HTMLFilter類,注意在doFilter當中調用了chain.doFilter(request,response, chain);
package com.bjsxt.dp.filter;
publicclass HTMLFilter implements Filter {
//@Override
publicvoid doFilter(Request request, Response response, FilterChainchain) {
//process the html tag<>
// 首先處理的request
request.requestStr = request.requestStr.replace('<', '[')
.replace('>', ']') + "---HTMLFilter()";
// 在request處理完成,之後馬上調用下一個filter
chain.doFilter(request, response, chain);
response.responseStr += "---HTMLFilter()";
}
}
SesitiveFilter類,注意在doFilter當中調用了chain.doFilter(request,response, chain);
package com.bjsxt.dp.filter;
publicclass SesitiveFilter implements Filter {
//@Override
publicvoid doFilter(Request request, Response response, FilterChainchain) {
//首先處理的request
request.requestStr = request.requestStr.replace("被就業", "就業")
.replace("敏感", "") + "---SesitiveFilter()";
//在request處理完成,之後馬上調用下一個filter
chain.doFilter(request, response, chain);
response.responseStr += "---SesitiveFilter()";
}
}
FilterChain類,大遞歸,反覆調用doFilter方法。
package com.bjsxt.dp.filter;
import java.util.ArrayList;
import java.util.List;
publicclass FilterChain implements Filter {
List<Filter> filters = new ArrayList<Filter>();
//記錄index
intindex = 0;
public FilterChain addFilter(Filter f) {
this.filters.add(f);
returnthis;
}
//@Override
publicvoid doFilter(Request request, Response response, FilterChainchain) {
//如果index已經走到了數組的最後。
if(index == filters.size()) return ;
//通過index來控制下一個filter是誰。
Filter f = filters.get(index);
//指向下一個filter
index ++;
f.doFilter(request, response, chain);
}
}
Request類
package com.bjsxt.dp.filter;
//模擬,從客戶端到服務器的信息,request
publicclass Request {
String requestStr;
public String getRequestStr() {
returnrequestStr;
}
publicvoid setRequestStr(String requestStr) {
this.requestStr = requestStr;
}
}
Response類
package com.bjsxt.dp.filter;
//模擬,從服務器到客戶端的信息,response
publicclass Response {
String responseStr;
public String getResponseStr() {
returnresponseStr;
}
publicvoid setResponseStr(String responseStr) {
this.responseStr = responseStr;
}
}
main類,使用者類:
package com.bjsxt.dp.filter;
//其核心過程,非常像一個大的遞歸程序。一路調用自己下去,然後一路反向返回。
publicclass Main {
/**
*@paramargs
*/
publicstaticvoid main(String[] args) {
String msg = "大家好:),<script>,敏感,被就業,網絡授課沒感覺,因爲看不見大家夥兒";
Request request = new Request();
request.setRequestStr(msg);
Response response = new Response();
response.setResponseStr("response");
FilterChain fc = new FilterChain();
fc.addFilter(new HTMLFilter())
.addFilter(new SesitiveFilter())
;
//在main裏面首先,把request和response對象傳進去,同時把自己也傳進去。
fc.doFilter(request, response, fc);
System.out.println(request.getRequestStr());
System.out.println(response.getResponseStr());
}
}
核心邏輯:
注意方法調用運行的順序:
在main方法當中開始運行,調用fc的doFilter。這個時候index爲0,fc的size是2.
在fc的filter當中,Filter f = filters.get(index); 這個時候拿到的是第一個filter。通過index++,這個時候index變成1了。
馬上通過fc的doFilter當中的f.doFilter調用第一個filter。這個時候,index爲0的這個fc.doFilter就暫停。程序就跳轉到HTMLfilter的doFilter當中。
這裏的f就是Filter f = filters.get(index);當中得到那個index=0的filter,也就是HTMLfilter,對request處理。request處理完成,馬上在HTMLfilter的doFilter方法調用了chain.doFilter.這個時候,HTMLfilter的doFilter方法暫停了。程序就跳轉到fc的doFilter當中。
那麼重新來到了fc的doFilter方法當中,要注意現在的index是1了。在fc的doFilter當中,Filter f =filters.get(index); 這個時候拿到的是第二個filter。拿到了第二個filter之後,通過index++,這個時候index變成2了。馬上通過f.doFilter調用第二個filter。這個時候,index爲1的這個fc.doFilter就也暫停。程序就跳轉到Sensitivefilter的doFilter當中。
這裏的f是Filter f = filters.get(index);當中得到那個index=1的filter,也就是第二個filter,是Sensitivefilter,對request處理。 request處理完成,馬上在Sensitivefilter的doFilter方法調用了chain.doFilter. 這個時候,Sensitivefilter的doFilter方法暫停了。程序就跳轉到fc的doFilter當中。
那麼再一次重新來到了fc的doFilter方法當中,現在的index是2了。因爲if(index == filters.size()) return ;現在index是2,所以就返回了。那麼request處理完畢。
返回的位置返回到上一個沒有執行完畢的方法,也就是最後一個調用chain.doFilter方法的位置。那麼來到Sensitivefilter的doFilter方法當中。Sensitivefilter就繼續執行,把處理response的業務邏輯完成。
Sensitivefilter的doFilter方法處理結束,就要返回到上一個沒有執行完畢的方法。也就是回到調用它的方法,也就是當index等於1的時候,fc.doFilter方法當中。
index等於1的fc.doFilter順利執行結束,那麼回到調用chain.doFilter的地方,也就是HTMLfilter的doFilter方法。
同樣HTMLfilter的doFilter方法繼續執行,把處理response的業務邏輯完成,返回到調用它的位置。也就是當index等於0的時候,fc.doFilter方法當中。
fc.doFilter順利執行結束, main方法結束。