【設計模式】通俗易懂版責任鏈模式

語言: CN / TW / HK

theme: juejin

引入

汽車生產過程中,必然要對汽車的各個部件,比如發動機、變速箱、車身等等進行嚴格的質量檢查,對不合格的部件進行過濾。

過濾檢查汽車部件

一般情況下,我們這樣寫就能實現了:

```java public class Client { public static void main(String[] args) { Client client = new Client();

    Request req = new Request();
    req.setReqMsg("檢查發動機,變速箱,車身有沒有問題");
    if (req.getReqMsg().contains("車身")) {
        client.doCheckCarbody();
    }
    if (req.getReqMsg().contains("發動機")) {
        client.doCheckEngine();
    }
    if (req.getReqMsg().contains("變速箱")) {
        client.doCheckGearbox();
    }
    if (req.getReqMsg().contains("xxx")) {
        // do something
    }
}

public void doCheckEngine () {
    System.out.println("------檢查了發動機------");
}

public void doCheckCarbody () {
    System.out.println("------檢查了車身-------");
}

public void doCheckGearbox () {
    System.out.println("------檢查了變速箱-----");
}

}

class Request { private String reqMsg;

public String getReqMsg() {
    return reqMsg;
}

public void setReqMsg(String reqMsg) {
    this.reqMsg = reqMsg;
}

} ``` but,看到

java if (req.getReqMsg().contains("xxx")) { // do something } 這個了嗎?這意味著檢查的東西增多,if語句也就變多了(好熟悉的程式碼,哈哈)

如何幹掉臃腫的if,優雅的執行汽車部件檢查?

針對上面的程式碼,如果哪天哪個部件獲得免檢了,不需要檢查了,還得去掉某一個if分支,這時候你就恨不得把所有程式碼都重構了。。。

面向物件有一個詞叫 封裝變化 ,也就是說 哪部分要變化,就封裝哪部分 ,我們可以對處理汽車部件的部分進行封裝。

程式碼如下: ```java public class Client { public static void main(String[] args) { Request req = new Request(); req.setReqMsg("檢查發動機,變速箱,車身有沒有問題");

    List<Filter> filters = new ArrayList<>();
    filters.add(new CarbodyFilter());
    filters.add(new GearboxFilter());
    filters.add(new EngineFilter());

    for (Filter f : filters) {
        f.doFilter(req);
    }
}

}

class Request { private String reqMsg;

public String getReqMsg() {
    return reqMsg;
}

public void setReqMsg(String reqMsg) {
    this.reqMsg = reqMsg;
}

}

interface Filter { boolean doFilter(Request request); }

class EngineFilter implements Filter { @Override public boolean doFilter(Request request) { if (request.getReqMsg().contains("發動機")) { System.out.println("------檢查了發動機------"); } return true; } }

class GearboxFilter implements Filter { @Override public boolean doFilter(Request request) { if (request.getReqMsg().contains("變速箱")) { System.out.println("------檢查了變速箱------"); } return true; } }

class CarbodyFilter implements Filter { @Override public boolean doFilter(Request request) { if (request.getReqMsg().contains("車身")) { System.out.println("------檢查了車身------"); } return true; } } ``` 這樣一來,如果要對哪個部件進行檢查,只需要向

java List<Filter> filters = new ArrayList<>(); filters裡新增Filter就行了,這個程式碼是不是稍微有那麼點意思了?

沒有最優雅,只有更優雅

上個版本的程式碼,仍需要在 Client 裡面的 List<Filter> 裡新增需要執行的 Filter ,還是差點意思。

我們來看一下上面描述的場景:

是不是每個 Filter 各司其職,只要把每個 Filter 串起來讓他們內部去執行就好了!

那我們來寫一個 FilterChain 來把他們串起來:

```java class FilterChain implements Filter { List filters = new ArrayList<>();

//比較騷的寫法,這樣可以鏈式呼叫
public FilterChain add(Filter filter) {
    filters.add(filter);
    return this;
}
//一般寫法

// public void add(Filter filter) { // filters.add(filter); // }

@Override
public boolean doFilter(Request request) {
    for (Filter f : filters) {
        //任何一環檢查出了問題,均不往下檢查
        if (!f.doFilter(request)) {
            return false;
        }
    }
    return true;
}

} `` 這裡提一下FilterChain中的add`方法,先看一般寫法:

java public void add(Filter filter) { filters.add(filter); } 然後呼叫就得這樣來搞: java FilterChain chain = new FilterChain(); chain.add(new EngineFilter()); chain.add(new GearboxFilter()); chain.add(new CarbodyFilter()); chain.doFilter(req); 有一種比較騷的寫法:

java public FilterChain add(Filter filter) { filters.add(filter); return this; }

呼叫: java FilterChain chain = new FilterChain(); chain.add(new EngineFilter()) .add(new GearboxFilter()) .add(new CarbodyFilter()) .doFilter(req);

咦?我在xx原始碼見過這個寫法!感覺瞬間提升了幾個檔次。

上面的 FilterChain 版本,其實就是 責任鏈模式 !!!

似曾相識的FilterChain

沒錯,如果你開發過Java Web程式,你一定見過這個東西。

比如 ServletFilterStrutsInterceptorSpring MVCHandlerInterceptor 。它們本質上都是過濾器或者叫攔截器。

JavaEE Filter

我用剛才的場景

模擬了一下FilterFilterChain

```java public class Client { public static void main(String[] args) { Request request = new Request(); request.reqMsg = "檢查發動機,變速箱,車身有沒有問題"; Response response = new Response(); response.respMsg = "-------response:";

    FilterChain chain = new FilterChain();
    chain.add(new EngineFilter()).add(new GearboxFilter()).add(new CarbodyFilter());
    chain.doFilter(request, response);

    System.out.println(response.respMsg);
}

}

class Request { String reqMsg; }

class Response { String respMsg; }

interface Filter { void doFilter(Request request, Response response, FilterChain chain); }

class EngineFilter implements Filter { public void doFilter(Request request, Response response, FilterChain chain) { //先處理request請求 if (request.reqMsg.contains("發動機")) { System.out.println("------EngineFilter 檢查了發動機------"); } //通過鏈條傳遞處理下一個request chain.doFilter(request, response); //處理response response.respMsg += "---執行了EngineFilter過濾器---"; } }

class GearboxFilter implements Filter { public void doFilter(Request request, Response response, FilterChain chain) { if (request.reqMsg.contains("變速箱")) { System.out.println("------GearboxFilter 檢查了變速箱------"); } //通過鏈條傳遞處理下一個request chain.doFilter(request, response); //處理response response.respMsg += "---執行了GearboxFilter過濾器---"; } }

class CarbodyFilter implements Filter { public void doFilter(Request request, Response response, FilterChain chain) { if (request.reqMsg.contains("車身")) { System.out.println("------CarbodyFilter 檢查了車身------"); } //通過鏈條傳遞處理下一個request chain.doFilter(request, response); //處理response response.respMsg += "---執行了CarbodyFilter過濾器---"; } }

class FilterChain { List filters = new ArrayList<>(); int filterIndex = 0;

public FilterChain add(Filter filter) {
    filters.add(filter);
    return this;
}

public void doFilter(Request request, Response response) {
    //如果request鏈條執行完了,就不往下傳遞了
    if (filterIndex == filters.size()) {
        return;
    }
    Filter f = filters.get(filterIndex);
    filterIndex++;
    f.doFilter(request, response, this);
}

} ``` 捋一捋:

FilterChain 裡面定義了一個 filterIndex 來控制鏈條順序執行,並且在每個filter的doFilter裡 1. 先處理request 2. 呼叫chain.doFilter(request, response)傳遞鏈條 3. 處理response

看下執行結果:

這些框架的過濾器、攔截器使用的也是 責任鏈模式

小結

  • 責任鏈模式 (Chain of Responsibility)是一種 處理請求 的模式,它讓多個處理器都有機會處理該請求,直到其中某個處理成功為止。責任鏈模式把多個處理器串成鏈,然後讓請求在鏈上傳遞。
  • 責任鏈模式在新增新的處理類或者排列處理請求的順序上非常容易。
  • 攔截、預處理請求等場景下經常會用到責任鏈模式。

暗示自己:好好學習設計模式,咱也能寫出優秀的程式碼!!!

以上。

點個贊再走吧~

我正在參與掘金技術社群創作者簽約計劃招募活動,點選連結報名投稿