責任鏈模式

責任鏈模式,web容器的filter,struts2的intercepter都是用的這個設計模式,一般常用的if,else,switch,case也都是用的這個模式,設計好一個處理流程,挨個流程節點進行處理!具體寫個例子程序!

 

如上圖所示,有一個類(也可做成接口):Handler,內含一個handler對象successor表明責任鏈的下一個處理節點,返回值爲handler,可以實現鏈式編程,處理方法handlerRequest,繼承或實現的類:characterHandler,symbolHandler,numberHanler,使用類:application實現責任鏈的設計,及使用。(此處封裝的不夠好~

Handler類:

public class Handler{

    private Handler successor;

   publicHandlersetSuccessor(Handler successor) {//這樣就很方便的可以用鏈式編程了,但是不符合set,get默認生成的方法的模式。。不知道如果在spring中進行註冊時會不會有問題。。

        this.successor = successor;//設計調用順序時

    }

    public Handler getSuccessor() {//用責任鏈進行處理時,實現這個處理節點對下一個處理節點的調用

        return successor;

    }

   public voidhandleRequest(char c) {//處理方法

        if(successor != null)

            successor.handleRequest(c);

    } }

numberHandler類,繼承handler,並重寫handlerRequest方法進行數字的處理,若不是數據的話,進入下一個處理器,這裏實現了鏈式調用!

public classNumberHandler extends Handler {

    public void handleRequest(char c) {

        if(Character.isDigit(c)) {

            System.out.println("Number hasbeen handled");

        } else {

            getSuccessor().handleRequest(c);

       }}}

CharacterHandler類,繼承handler,並重寫handlerRequest方法。

public classCharacterHandler extends Handler {

    public void handleRequest(char c) {

        if(Character.isLetter(c)) {

            System.out.println("Characterhas been handled");

        }else {

            getSuccessor().handleRequest(c);

       }}}

SymbolHandler直接做處理,沒有調用過程!這是責任鏈的最後一道關口~~

public classSymbolHandler extends Handler {

    public void handleRequest(char c) {

        System.out.println("Symbol hasbeen handled");

   }}

Application真實的實用類,定義了責任鏈的整個調用順序!

public classApplication {

    public static void main(String[]args)throws IOException {

        Handler numberHandler = newNumberHandler();

        Handler characterHandler = newCharacterHandler();

        Handler symbolHandler = newSymbolHandler();

        numberHandler.setSuccessor(characterHandler)

.setSuccessor(symbolHandler);//進行鏈式編程,很方便!而且定義鏈子很直觀!

       char c = 'A';

        numberHandler.handleRequest(c);

    }}


這就是責任鏈,還是很簡單的!

(以下摘自別人的博客:http://hwhuang.iteye.com/blog/648032,對比發現,首先說明問題比我要清晰很多,這說明理解比我透徹,並且表述能力比我強很多;其次,有總結且很到位,說明概括能力強,並且,理解深刻。。)


而在Struts2中,其攔截器結構的設計,是一個典型的責任鏈模式的應用。首先將整個執行劃分成若干相同類型的元素,每個元素具備不同的邏輯責任,並將他們納入到一個鏈式的數據結構中(我們可以把堆棧結構也看作是一個遞歸的鏈式結構),而每個元素又有責任負責鏈式結構中下一個元素的執行調用。 這樣的設計,從代碼重構的角度來看,實際上是將一個複雜的系統,分而治之,從而使得每個部分的邏輯能夠高度重用並具備高度可擴展性。所以,Interceptor結構實在是Struts2/Xwork設計中的精華之筆。

Struts2攔截器執行機理如下:

1.整個結構就如同一個堆棧,除了Action以外,堆棧中的其他元素是Interceptor

2.Action位於堆棧的底部。由於堆棧"先進後出"的特性,如果我們試圖把Action拿出來執行,我們必須首先把位於Action上端的Interceptor拿出來執行。這樣,整個執行就形成了一個遞歸調用

3.每個位於堆棧中的Interceptor,除了需要完成它自身的邏輯,還需要完成一個特殊的執行職責。這個執行職責有3種選擇:

1)中止整個執行,直接返回一個字符串作爲resultCode

2)通過遞歸調用負責調用堆棧中下一個Interceptor的執行

3)如果在堆棧內已經不存在任何的Interceptor,調用Action


另一個大牛對責任鏈更深入的理解:

使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它爲止。

適用場景:

1、有多個的對象可以處理一個請求,哪個對象處理該請求運行時刻自動確定;

2、在不明確指定接收者的情況下,向多個對象中的一個提交一個請求;

3、處理一個請求的對象集合應被動態指定。

具體實例:

在大學裏面當班幹部,時常要向上級申請各方面的東西。譬如申請全班外出秋遊,普通同學將申請表交給班長,班長簽字之後交給輔導員,輔導員批准之後上交到主任辦公室…就是這樣,一個請求(這裏是一份申請表)有時候需要經過好幾個級別的處理者(這裏是輔導員、主任)的審查才能夠最終被確定可行與否。

在這裏表現出來的是一個職責鏈,即不同的處理者對同一個請求可能擔負着不同的處理方式、權限,但是我們希望這個請求必須到達最終拍板的處理者(否則秋遊就沒戲了)。這種關係就很適合使用職責鏈模式了。

記得第一次看到職責鏈模式的時候,我很驚訝於它能夠把我們平時在代碼中的 if..else.. 的語句塊變成這樣靈活、適應變化。例如:如果現在輔導員請長假了,但我們的秋遊還是要爭取申請成功呀,那麼我們在 Client 類中可以不要創建 handler02,即不要將該處理者組裝到職責鏈中。這樣子處理比 if..else..好多了。或者說,突然來了個愛管閒事的領導,那麼我照樣可以將其組裝到職責鏈中。
 
關於上面使用場景中提到的3個點:
1、處理者在運行時動態確定其實是我們在 Client 中組裝的鏈所引起的,因爲具體的職責邏輯就在鏈中一一對應起來;
2、因爲不確定請求的具體處理者是誰,所以我們把所有可能的處理者組裝成一條鏈,在遍歷的過程中就相當於向每個處理者都提交了這個請求,等待其審查。並且在審查過程中,即使不是最終處理者,也可以進行一些請求的“包裝”操作(這種功能類似於裝飾者模式),例如上面例子中的簽名批准;
3、處理者集合的動態指定跟上面的第1、2點類似,即在 Client 類中創建了所有可能的處理者。
 
不足之處:

1、對於每一個請求都需要遍歷職責鏈,性能是個問題;

2、抽象處理者 AbstractHandler 類中的 handleRequest() 方法中使用了遞歸,棧空間的大小也是個問題。

 個人看法:

職責鏈模式對於請求的處理是不知道最終處理者是誰,所以是運行動態尋找並指定;而命令模式中對於命令的處理時在創建命令是已經顯式或隱式綁定了接收者。

到這吧,這篇文章有點長,而且都是別人的東西,自己都沒整理,甚至有點沒理解透就網上貼了,現下12:38有點困了。。。


發佈了66 篇原創文章 · 獲贊 9 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章