設計模式之責任鏈(ChainOfResponsibility)

責任鏈(ChainOfResponsibility)

對於設計模式的學習,必定要動手,並且要屢次練習,而後慢慢消化和理解,才能明白其精髓。可是,設計模式只是在特殊情景下的特殊解決方案,不要濫用,不要爲了使用設計模式而硬生生得去使用。設計模式的使用應該天然、優雅!java

問題

1 public class TestMain {
2 public static void main(String[] args) {
3     String str = "你好:),這句話中有敏感詞彙,須要處理。<script>,敏感!";
4     MsgProcessor pro = new MsgProcessor();
5     pro.setMsg(str);
6     str = pro.processor();---
7     System.out.println(str);
8 }
9 }

另外一個類:web

01 public class MsgProcessor {
02 private String msg;
03 public String getMsg() {
04     return msg;
05 }
06 public void setMsg(String msg) {
07     this.msg = msg;
08 }
09
10 public String processor(){
11     String content = "";
12     if(null != msg && !("").equals(msg.trim())){
13         content = msg.replace("<", "{")
14         .replace(">", "}");
15
16         content = content.replace("敏感", "");
17         content = content.replace(":)", "^V^");
18     }
19     return content;
20
21 }

上面的代碼完成了對一個字符串的簡單過濾,可是很明顯這樣的代碼很很差。擴展性很差,寫得也不夠好。這樣之後須要添加別的過濾功能不是很方便,老是要修改這個類,一點都不靈活,想把對字符串的過濾行爲抽象出來,由於這部分是變化的,天然而然想到使用接口。編程

使用接口來剝離行爲

代碼修改成:設計模式

1 public String processor(){
2     if(null != msg && !("").equals(msg.trim())){
3         msg = new HTMLFilter().doFilter(msg);
4         msg = new SmileFilter().doFilter(msg);
5         msg = new SensitivityFilter().doFilter(msg);
6     }
7     return msg;
8 }

這樣仍是不夠靈活,直接在  MsgProcessor  類中添加一個數組來保存過濾器,而後在  processor** 方法中進行屢次調用:數組

修改成:數據結構

1 public String processor(){
2     if(null != msg && !("").equals(msg.trim())){
3         for(Filter f : filters){
4             msg = f.doFilter(msg);
5         }
6     }
7     return msg;
8 }

這樣調整後,全部的過濾器都起做用了,添加起來更加靈活一些,而且過濾器的執行順序也是可控的。ide

當多個過濾器組合在一塊兒,就造成了過濾器鏈,到這裏,責任鏈有點雛形了。學習

新的問題

若是原本已經存在一個過濾器鏈條了,我想把一些新的過濾器鏈加進去,而且加入的順序能夠隨意控制(隨意組合任意的過濾器鏈條),該怎麼辦呢?this

定義一個過濾器鏈類,這這個類中定義添加過濾器的方法,以及運行整個鏈條上的全部過濾器的方法,而且返回結果。url

代碼修改成:

MsgProcessor.java :

01 public class MsgProcessor {
02 private String msg;
03
04 private FilterChain fc;
05
06 public FilterChain getFc() {
07     return fc;
08 }
09 public void setFc(FilterChain fc) {
10     this.fc = fc;
11 }
12 public String getMsg() {
13     return msg;
14 }
15 public void setMsg(String msg) {
16     this.msg = msg;
17 }
18
19 public String processor(){
20     return fc.doFilter(msg);
21 }
22 }

FilterChain.java:

01 public class FilterChain {
02 List<Filter> filters = new ArrayList<Filter>();
03
04 public FilterChain addFilter(Filter filter){
05     filters.add(filter);
06     return this;
07 }
08
09 public String doFilter(String str){
10     if(null != str && !("").equals(str.trim())){
11         for(Filter f : filters){
12             str = f.doFilter(str);
13         }
14     }
15     return str;
16 }
17 }

TestMain.java

01 public class TestMain {
02 public static void main(String[] args) {
03     String str = "你好:),這句話中有敏感詞彙,須要處理。<script>,敏感!";
04     MsgProcessor mp = new MsgProcessor();
05     mp.setMsg(str);
06     FilterChain fc = new FilterChain();
07     fc.addFilter(new HTMLFilter())
08     .addFilter(new SmileFilter())
09     .addFilter(new SensitivityFilter());
10     mp.setFc(fc);
11     str = mp.processor();
12     System.out.println(str);
13 }
14 }

寫到這裏,仍是沒有解決咱們的問題,怎樣靈活合併過濾器鏈呢? 很簡單,咱們能夠將過濾器鏈這個類,看成一個很大的過濾器來處理,這樣就能夠了。讓 FilterChain 也實現Filter接口,這樣就解決了這個問題!完成這一步,就已經有了責任鏈模式的味道了!

思考實際開發中的問題

在實際開發中,咱們見過的過濾器都能進行雙向的處理,也就是說,能處理request和response,並且是先挨着處理request,而後再反向處理response,這又是怎麼實現的呢?
過濾器鏈圖

定義一個Request和Response,在實際的web容器中,容器會幫助咱們生成這兩個對象,並且在其中封裝了不少的東西,在這裏,只是模擬,只需簡單定義就能夠了。

Request.java

1 public class Request {
2 private String requestStr;
3 public String getRequestStr() {
4     return requestStr;
5 }
6 public void setRequestStr(String requestStr) {
7     this.requestStr = requestStr;
8 }
9 }

Response.java

1 public class Response {
2 private String responseStr;
3 public String getResponseStr() {
4     return responseStr;
5 }
6 public void setResponseStr(String responseStr) {
7     this.responseStr = responseStr;
8 }
9 }

定義好這兩個類以後,修改以前的程序:

Filter.java

1 public interface Filter {
2     public abstract void doFilter(Request request, Response response);
3 }

別的代碼跟着這個接口一塊兒改就能夠了,可是你會發現,仍是不能實現咱們想要的效果,這個時候須要一些編程的手法,咱們繼續修改Filter接口:

Filter.java

1 public interface Filter {
2     public abstract void doFilter(Request request, Response response, FilterChain filterChain);
3 }

爲何要這樣修改,由於只有這樣才能把鏈條握在每個過濾器手中,有了鏈條,就能夠控制鏈條了:

FilterChain.java

01 public class FilterChain implements Filter {
02 private List<Filter> filters = new ArrayList<Filter>();
03 private int index = 0;
04 public FilterChain addFilter(Filter filter){
05     this.filters.add(filter);
06     return this;
07 }
08 @Override
09 public void doFilter(Request request, Response response,
10         FilterChain filterChain) {
11     if(index >= filters.size()) return;
12     Filter f = filters.get(index);
13     index++;
14     f.doFilter(request, response, filterChain);
15 }
16 }

HTMLFilter.java

01 public class HTMLFilter implements Filter {
02 @Override
03 public void doFilter(Request request, Response response,
04         FilterChain filterChain) {
05     String str = request.getRequestStr();
06     System.out.println(str);
07     filterChain.doFilter(request, response, filterChain);
08     String resStr = response.getResponseStr();
09     System.out.println(resStr);
10 }
11 }

如今來看,每一個過濾器都持有過濾器鏈,在處理完request後,調用下一個過濾器,因爲方法是棧結構,這樣就會造成一個過濾器棧,擁有棧的數據結構特色。這也是爲何Struts在配置多個攔截器的時候,成爲攔截器棧的緣由。 因爲棧的數據特色,就能達到咱們想要的特色,按照過濾器的次序,依次處理完request,而後再反向依次處理response。這就是責任鏈模式在實際開發中的使用。

相關文章
相關標籤/搜索