設計模式 | 職責鏈模式(Chain of responsibility)

定義:

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

結構:(書中圖,侵刪)

 

一個抽象的處理者
若干個具體處理者(每個具體處理者都不知道它的繼任者是誰,這個繼任者由客戶端決定,只負責把處理不了的請求轉發給繼任者)

實例:

工作流基本都可以用這個模式來設計。
我就來寫個生產醬板鴨的流水線好了。
屠宰-》清洗-》滷製-》風乾-》包裝
簡化一點,懶得寫那麼多類
清洗-》滷製-》包裝

 鴨子類:

package designpattern.chainofresponsibility;

public class Duck {
    public State state;

    Duck(State state) {
        this.state = state;
    }

    public enum State {
        DIRTY, CLEAN, COOKED, PACKAGED
    }

    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }

}

抽象處理者類:

package designpattern.chainofresponsibility;

public abstract class Handler {
    protected Handler successor;

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

    public abstract void handleDuck(Duck duck);
}

清洗者類(具體處理者):

package designpattern.chainofresponsibility;

import designpattern.chainofresponsibility.Duck.State;

public class DuckCleaner extends Handler {

    @Override
    public void handleDuck(Duck duck) {
        if (duck.state == State.DIRTY) {
            System.out.println("清洗員-》清理鴨子~");
            duck.setState(State.CLEAN);
        } else {
            successor.handleDuck(duck);
        }
    }

}

廚師類(具體處理者):

package designpattern.chainofresponsibility;

import designpattern.chainofresponsibility.Duck.State;

public class DuckCook extends Handler {
    @Override
    public void handleDuck(Duck duck) {
        if (duck.state == State.CLEAN) {
            System.out.println("廚師-》滷製鴨子~");
            duck.setState(State.COOKED);
        } else {
            successor.handleDuck(duck);
        }
    }
}

打包者類(具體處理者):

package designpattern.chainofresponsibility;

import designpattern.chainofresponsibility.Duck.State;

public class DuckPackager extends Handler {
    @Override
    public void handleDuck(Duck duck) {
        if (duck.state == State.COOKED) {
            System.out.println("打包員-》包裝鴨子~");
            duck.setState(State.PACKAGED);
        }
    }
}

客戶端:

package designpattern.chainofresponsibility;

import designpattern.chainofresponsibility.Duck.State;

public class Client {
    public static void main(String[] args) {
        DuckCleaner duckCleaner = new DuckCleaner();
        DuckCook duckCook = new DuckCook();
        DuckPackager duckPackager = new DuckPackager();
        duckCleaner.setSuccessor(duckCook);
        duckCook.setSuccessor(duckPackager);

        // 處理臟鴨子
        Duck duck = new Duck(State.DIRTY);
        duckCleaner.handleDuck(duck);
        // 處理鹵好的鴨子
        duck.setState(State.COOKED);
        duckCleaner.handleDuck(duck);
    }
}

結果輸出:

清洗員-》清理鴨子~
打包員-》包裝鴨子~
不管鴨子在哪個狀態,統統傳給清理者,他處理不了,會一路傳下去,直到正確的人來處理。

總結:

這個模式算是一個結構比較簡單的,也很好理解,只不過之前自己想的時候完全沒有想出來可以用這樣的方式來實現。
又能把請求傳遞下去又能讓處理者之間,以及處理者和客戶端之間解耦,真的很巧妙。
不過像上面說的,繼任者是由客戶端決定的,但實際上具體處理者之間有潛在的邏輯關係,如果客戶端沒有正確的設置鏈條可能會導致請求得不到處理。
比如上面的例子,直接拿洗好的鴨子去包裝顯然是包裝不了的。
所以需要把文檔寫得足夠清晰,以供客戶端正確使用。