設計模式之5 責任鏈

責任鏈就是通過一連串的過濾器(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,並且分別調用每個filterdoFilter方法。

 

專門的字符串處理類:

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當中,那麼就有兩個fcfc1fc2

       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;

    }

   

    //其實調用的是filterChaindoFilter方法,還是把每個Filter拿出來,每個執行一遍doFilter方法。

    //現在其實process自己什麼都不做,都是FC來處理。

    public String process() {

      

      

       returnfc.doFilter(msg);

      

      

    }

}

 

FilterChain當中可以添加和刪除filter。本例中只實現了添加,沒實現刪除。要注意的是,這些filter需要根據使用者的需求(選擇哪些filterfilter的順序),在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;

 

//現在的參數,就是requestresponse,還有chain

//傳遞的時候,可以是request+空的response

//或者是response+空的request

//注意現在的返回值,不再是string類型,而是把處理完成的信息保存在requestresponse對象當中。

//所以返回值爲void

publicinterface Filter {

   

    //FilterChain在這裏的意義: filterFC裏面,如果給定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裏面首先,把requestresponse對象傳進去,同時把自己也傳進去。

       fc.doFilter(request, response, fc);

       System.out.println(request.getRequestStr());

       System.out.println(response.getResponseStr());

    }

 

}

 

 

核心邏輯:

      

   注意方法調用運行的順序:

      main方法當中開始運行,調用fcdoFilter。這個時候index0fcsize2.

     fcfilter當中,Filter f = filters.get(index); 這個時候拿到的是第一個filter。通過index++,這個時候index變成1了。

      馬上通過fcdoFilter當中的f.doFilter調用第一個filter。這個時候,index0的這個fc.doFilter就暫停。程序就跳轉到HTMLfilterdoFilter當中。

      這裏的f就是Filter f = filters.get(index);當中得到那個index=0filter,也就是HTMLfilter,對request處理。request處理完成,馬上在HTMLfilterdoFilter方法調用了chain.doFilter.這個時候,HTMLfilterdoFilter方法暫停了。程序就跳轉到fcdoFilter當中。

      那麼重新來到了fcdoFilter方法當中,要注意現在的index1了。在fcdoFilter當中,Filter f =filters.get(index); 這個時候拿到的是第二個filter。拿到了第二個filter之後,通過index++,這個時候index變成2了。馬上通過f.doFilter調用第二個filter。這個時候,index1的這個fc.doFilter就也暫停。程序就跳轉到SensitivefilterdoFilter當中。

      這裏的fFilter f = filters.get(index);當中得到那個index=1filter,也就是第二個filter,是Sensitivefilter,對request處理。 request處理完成,馬上在SensitivefilterdoFilter方法調用了chain.doFilter. 這個時候,SensitivefilterdoFilter方法暫停了。程序就跳轉到fcdoFilter當中。

      那麼再一次重新來到了fcdoFilter方法當中,現在的index2了。因爲if(index == filters.size()) return ;現在index2,所以就返回了。那麼request處理完畢。

 

      返回的位置返回到上一個沒有執行完畢的方法,也就是最後一個調用chain.doFilter方法的位置。那麼來到SensitivefilterdoFilter方法當中。Sensitivefilter就繼續執行,把處理response的業務邏輯完成。

      SensitivefilterdoFilter方法處理結束,就要返回到上一個沒有執行完畢的方法。也就是回到調用它的方法,也就是當index等於1的時候,fc.doFilter方法當中。

      index等於1fc.doFilter順利執行結束,那麼回到調用chain.doFilter的地方,也就是HTMLfilterdoFilter方法。

      同樣HTMLfilterdoFilter方法繼續執行,把處理response的業務邏輯完成,返回到調用它的位置。也就是當index等於0的時候,fc.doFilter方法當中。

      fc.doFilter順利執行結束, main方法結束。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章