軟件體系結構--責任鏈模式

概念

責任鏈模式爲某個請求創建一個對象鏈,每個對象依次檢查此請求,並對其進行處理,或者將它傳給鏈中的下一個對象。

鏈表是很常見一種數據結構,責任鏈模式的結構其實和鏈表相差無幾,唯一的區別就是責任鏈模式中所有的對象都有一個共同的父類(或接口):

image

在責任鏈模式中,N個 Handler 子類都處理同一個請求,只不過具體的職責有所差別。

當有一個請求進入時,先經過 AHandler 的 handlerRequest 方法,然後再把請求傳遞給 BHandler,B 處理完再把請求傳遞給 CHandler,以此類推,形成一個鏈條。鏈條上的每一個對象所承擔的責任各不相同,這就是責任鏈模式。

例子

現在我們模擬一個場景:論壇用戶發表帖子,但是常常會有用戶一些不良的信息,如廣告信息,涉黃信息,涉及政治的敏感詞等。這時我們就可以使用責任鏈模式來過濾用戶發表的信息。

先定義所有責任鏈對象的父類:

/**
 * 帖子處理器
 */
public abstract class PostHandler {

    /**
     * 後繼者
     */
    protected PostHandler successor;

    public void setSuccessor(PostHandler handler){
        this.successor = handler;
    }

    public abstract void handlerRequest(Post post);

    protected final void next(Post post){
        if(this.successor != null){
            this.successor.handlerRequest(post);
        }
    }
}

父類 Handler 主要封裝了傳遞請求等方法,其中要注意的有兩點:

  • successor,後繼者,這個屬性很重要,它保存了責任鏈中下一個處理器
  • 在 next() 方法中(方法名自己隨便取),當請求傳遞到最後一個責任對象時,已經沒有後繼者繼續處理請求了,因此要對 successor 做判空處理,避免拋出空指針異常。
  • 處理請求的handlerRequest 的入參和返回類型可以根據實際情況修改,可以在該方法中拋出異常來中斷請求

廣告處理器:

/**
 * 廣告處理器
 */
public class AdHandler extends PostHandler {

    @Override
    public void handlerRequest(Post post) {
        //屏蔽廣告內容
        String content = post.getContent();
        //.....
        content = content.replace("廣告","**");
        post.setContent(content);

        System.out.println("過濾廣告...");
        //傳遞給下一個處理器
        next(post);
    }
}

涉黃處理器:

/**
 * 涉黃處理器
 */
public class YellowHandler extends PostHandler {

    @Override
    public void handlerRequest(Post post) {
        //屏蔽涉黃內容
        String content = post.getContent();
        //.....
        content = content.replace("涉黃","**");
        post.setContent(content);

        System.out.println("過濾涉黃內容...");
        //傳遞給下一個處理器
        next(post);
    }
}

調用:

//創建責任對象
PostHandler adHandler = new AdHandler();
PostHandler yellowHandler = new YellowHandler();
PostHandler swHandler = new SensitiveWordsHandler();

//形成責任鏈
yellowHandler.setSuccessor(swHandler);
adHandler.setSuccessor(yellowHandler);

Post post = new Post();
post.setContent("我是正常內容,我是廣告,我是涉黃,我是敏感詞,我是正常內容");

System.out.println("過濾前的內容爲:"+post.getContent());

post = adHandler.handlerRequest(post);

System.out.println("過濾後的內容爲:"+post.getContent());

總結

可能大家有疑問,爲什麼不把所有的過濾器寫在一個方法裏呢?因爲這樣做又破壞了開放封閉原則。我們需要使用責任鏈模式,能夠在不修改已有代碼的情況下擴展新功能。

責任鏈模式將常用於過濾器,攔截器,事件(鼠標鍵盤事件,冒泡事件等)等場景

優點

  • 請求者和接收者解耦
    可以動態的增加或減少責任鏈上的對象,或者修改順序

缺點

  • 調用者不知道請求可能被哪些責任鏈對象處理,不利於排錯
    用戶請求可能被責任鏈中途攔截,最終未必被真正執行,這點既是優點也是缺點,我們可以利用它做權限控制攔截器
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章