1. 程式人生 > >責任鏈模式——ChainOfResponsibility

責任鏈模式——ChainOfResponsibility

案例展示——ChainOfResponsibility怎麼用?

 考慮這樣一個場景:現有一家工廠(大型綜合一體化工廠),從原料生產到成品出產都由這家工廠獨立完成。為了便於管理與提高效率,只能明確,工廠領導層決定將工廠一分為三:原料廠負責原料的生產和購買,零件製造廠負責零部件的製造,裝配廠負責裝配出廠。同時為了便於監管,督促各大工廠之間保質保量的完成任務,領導層委派很多監察者去各大工廠監察,每個監察者都有自己特定監察的工廠:原料廠監察者負責監察原料廠,零件製造廠監察者負責監察零件製造廠,裝配廠監察者負責監察裝配廠,每個人都各司其職。下面是類圖設計:

image

分析上面的類圖如下:

  • ISupervisor:監察者介面,可以獲得監察者的監察請求和身份

  • Supervisor:具體的監察者,實現了ISupervisor介面

  • IHandler:有處理權的抽象人員介面

  • MaterialFactory,ProduceFactory,AssembleFactory:實現IHandler介面,具體的處理者

具體的程式碼實現如下:

//監察者介面
public interface ISupervisor {

    //獲得生產階段
    public int getStage();

    //獲得監察請求
    public String getRequest
(); } //監察者 public class Supervisor implements ISupervisor { /** * 表示監察者身份 * 1. 原料廠巡查 * 2. 零件製造廠巡查 * 3. 裝配廠巡查 */ private int stage = 0; //監察請求 private String request = ""; //建構函式傳遞請求 public Supervisor(int stage, String request) { this.stage = stage;
this.request = request; } public int getStage() { return this.stage; } public String getRequest() { return this.request; } } //抽象處理者 public interface IHandler { //監察者要來巡查,處理請求 public void HandlerMessage(ISupervisor supervisor); } //原料廠 public class MaterialFactory implements IHandler{ //監察者要求巡查原料廠 public void HandlerMessage(ISupervisor supervisor) { System.out.println("原料廠監察者巡查:" + supervisor.getRequest()); System.out.println("原料廠回覆:保質保量!"); } } //零件製造廠 public class ProduceFactory implements IHandler { //監察者要求巡查零件製造廠 public void HandlerMessage(ISupervisor supervisor) { System.out.println("零件製造廠監察者巡查:" + supervisor.getRequest()); System.out.println("製造廠回覆:做工精良!"); } } //裝配廠 public class AssembleFactory implements IHandler { //監察者要求巡查裝配廠 public void HandlerMessage(ISupervisor supervisor) { System.out.println("裝配廠監察者巡查:" + supervisor.getRequest()); System.out.println("裝配廠回覆:效率第一!"); } } //在一個場景類中執行程式碼 public class Client { public static void main(String[] args) { //產生多個監察者(身份隨機) Random random = new Random(); ArrayList<ISupervisor> list = new ArrayList<ISupervisor>(); for (int i = 0; i < 5; i++) { list.add(new Supervisor(random.nextInt(4), "我將來巡查,做好準備!")); } //定義三個請示物件 Handler material = new MaterialFactory(); Handler producer = new ProduceFactory(); Handler assemble = new AssembleFactory(); //設定順序 material.setNextHandler(producer); producer.setNextHandler(assemble); for (ISupervisor supervisor : list) { material.HandlerMessage(supervisor); } } } //結果如下: ===========去原料廠巡查========== 原料廠監察者巡查:我將來巡查,做好準備! 原料廠回覆:保質保量! ===========去零件製造廠巡查========== 零件製造廠監察者巡查:我將來巡查,做好準備! 製造廠回覆:做工精良! ===========去裝配廠巡查========== 裝配廠監察者巡查:我將來巡查,做好準備! 裝配廠回覆:效率第一!

 觀察了上面的設計與程式碼實現,雖然得到了我們想要的結果,但是卻有幾個地方需要改進:

  • 高層模組對低層模組依賴太深,不利於擴充套件:對於監察者的身份與檢查請求,應該由具體的處理類去得到,而不應該由高層模組去邏輯判斷指定

  • 耦合過重:我們需要根據監察者的身份來決定使用IHandler的哪個實現類,但是假如IHandler的實現類繼續擴充套件,我們將不得不去修改高層模組(Client類)

 所以正確的處理請求應該是這樣的,首先,每個工廠應該提前知道監察者的身份,判斷自己能否接受監察,如果不能將其傳遞給下一個工廠。下面是類圖設計:

image

分析上面的類圖如下:

  • Handler:使用了模板方法模式,在模板方法中判斷監察者的身份和自己能否做出處理,如果能處理則做出反饋,如果不能處理就傳遞給下一個環節,直到環節結束。基本方法response需要每個實現類去實現,每個實現類只實現兩個職責:1. 定義自己能夠接納的監察者身份;2. 對請求做出迴應

下面是具體的程式碼實現:

//監察者介面
public interface ISupervisor {

    //獲得生產階段
    public int getStage();

    //獲得監察請求
    public String getRequest();
}

//監察者
public class Supervisor implements ISupervisor{
    /**
     * 表示監察者身份
     * 1. 原料廠巡查
     * 2. 零件製造廠巡查
     * 3. 裝配廠巡查
     */
    private int stage = 0;

    //監察者請求
    private String request = "";

    //建構函式傳遞請求
    public Supervisor(int stage, String request) {
        this.stage = stage;

        switch (this.stage) {
            case 1:
                this.request = "原料廠監察者巡查:" + request;
                break;
            case 2:
                this.request = "零件製造廠監察者巡查:" + request;
                break;
            case 3:
                this.request = "裝配廠監察者巡查:" + request;
        }
    }

    public int getStage() {
        return this.stage;
    }

    public String getRequest() {
        return this.request;
    }
}

//抽象處理類
public abstract class Handler {

    public final static int MATERIAL_STAGE = 1;
    public final static int PRODUCE_STAGE = 2;
    public final static int ASSEMBLE_STAGE = 3;

    //監察者身份:巡查對應身份的工廠
    private int stage = 0;

    //責任傳遞:不是對應的巡查請求向下傳遞
    private Handler nextHandler;

    //自己能接受誰的巡查
    public Handler(int stage) {
        this.stage = stage;
    }

    //監察者要來巡查,需要處理請求
    public final void HandlerMessage(ISupervisor supervisor) {
        if (supervisor.getStage() == this.stage) {
            this.response(supervisor);
        } else {
            if (this.nextHandler != null) { //後續環節
                this.nextHandler.HandlerMessage(supervisor);
            } else { //沒有後續處理人
                System.out.println("=======沒有可巡查的工廠了======");
            }
        }
    }
    /**
     * 不是對應的處理請求,傳遞給下一個
     */
    public void setNextHandler(Handler handler) {
        this.nextHandler = handler;
    }

    //進行迴應
    protected abstract void response(ISupervisor supervisor);
}

//原料廠
public class MaterialFactory extends Handler {
    //處理身份是原料廠監察者的請求
    public MaterialFactory() {
        super(Handler.MATERIAL_STAGE);
    }

    /**
     * 巡查原料廠
     */
    protected void response(ISupervisor supervisor) {
        System.out.println("===========去原料廠巡查==========");
        System.out.println(supervisor.getRequest());
        System.out.println("原料廠回覆:保質保量!");
    }
}

//零件製造廠
public class ProduceFactory extends Handler {
    //處理身份是零件製造廠監察者的請求
    public ProduceFactory() {
        super(Handler.PRODUCE_STAGE);
    }

    /**
     * 巡查零件製造廠
     */
    protected void response(ISupervisor supervisor) {
        System.out.println("===========去零件製造廠巡查==========");
        System.out.println(supervisor.getRequest());
        System.out.println("製造廠回覆:做工精良!");
    }
}

//裝配廠
public class AssembleFactory extends Handler {
    //處理身份是裝配廠監察者的請求
    public AssembleFactory() {
        super(Handler.ASSEMBLE_STAGE);
    }

    /**
     * 巡查裝配廠
     */
    protected void response(ISupervisor supervisor) {
        System.out.println("===========去裝配廠巡查==========");
        System.out.println(supervisor.getRequest());
        System.out.println("裝配廠回覆:效率第一!");
    }
}


//在一個場景類中執行程式碼
public class Client {

    public static void main(String[] args) {
        //產生多個監察者(身份隨機)
        Random random = new Random();
        ArrayList<ISupervisor> list = new ArrayList<ISupervisor>();
        for (int i = 0; i < 5; i++) {
            list.add(new Supervisor(random.nextInt(4), "我將來巡查,做好準備!"));
        }

        //定義三個請示物件
        Handler material = new MaterialFactory();
        Handler producer = new ProduceFactory();
        Handler assemble = new AssembleFactory();

        //設定順序
        material.setNextHandler(producer);
        producer.setNextHandler(assemble);
        for (ISupervisor supervisor : list) {
            material.HandlerMessage(supervisor);
        }
    }
}

//結果如下:
===========去原料廠巡查==========
原料廠監察者巡查:我將來巡查,做好準備!
原料廠回覆:保質保量!
===========去零件製造廠巡查==========
零件製造廠監察者巡查:我將來巡查,做好準備!
製造廠回覆:做工精良!
===========去裝配廠巡查==========
裝配廠監察者巡查:我將來巡查,做好準備!
裝配廠回覆:效率第一!

 我們發現結果是正確的,高層模組Client不用去主動判斷監察者的身份,而是由每個處理者自己去獲取,而且Handler可以自己擴充套件,只要設定好傳遞鏈就可以了,監察者的請求會在這條鏈上進行傳遞,會有對應的處理者去處理請求。這就是責任鏈模式

深入分析——ChainOfResponsibility是什麼?

ChainOfResponsibility的定義

定義: 使多個物件都有機會處理請求,從而避免了請求的傳送者和接受者之間的耦合關係。將這些物件連城一條鏈,並沿著這條鏈傳遞該請求,直到有物件處理它為止。下面是通用類圖:

image

責任鏈模式的核心: 由一條鏈去處理相似的請求,並在鏈中決定由誰來處理這個請求,同時返回相應的結果。

下面是通用程式碼:

//抽象處理者
public abstract class Handler {
    private Handler nextHandler;
    //每個處理者需要對請求作出處理
    public final Response handlerMessage(Request request) {
        Response response = null;
        //判斷是否是自己的處理級別
        if (this.getHandlerLevel().equals(request.getRequestLevel())) {
            response = this.echo(request);
        } else { //不屬於自己的處理級別
            //判斷是否有下一個處理者
            if (this.nextHandler != null) {
                response = this.nextHandler.handlerMessage(request);
            } else {
                //沒有適當處理者
            }
        }
        return response;
    }

    //設定下一個處理者
    public void setNextHandler(Handler handler) {
        this.nextHandler = handler;
    }

    //每個處理者對應的處理級別
    protected abstract Level  getHandlerLevel();

    //處理者實現自己的處理任務
    protected abstract Response echo(Request request);
}

//具體處理者
public class ConcreateHandler1 extends Handler {
    //處理邏輯
    protected Level getHandlerLevel() {
        return null;
    }

    //設定處理級別
    protected Response echo(Request request) {
        return null;
    }
}
public class ConcreateHandler2 extends Handler {
    //處理邏輯
    protected Level getHandlerLevel() {
        return null;
    }

    //設定處理級別
    protected Response echo(Request request) {
        return null;
    }
}
public class ConcreateHandler3 extends Handler {
    //處理邏輯
    protected Level getHandlerLevel() {
        return null;
    }

    //設定處理級別
    protected Response echo(Request request) {
        return null;
    }
}

//框架程式碼
public class Level {
    //定義請求和處理等級
}
public class Request {
    //請求的等級
    public Level getRequestLevel() {
        return null;
    }
}
public class Response {
    //處理者返回資料
}


//場景類
public class Client {
    public static void main(String[] args) {
        //宣告所有的處理者
        Handler handler1 = new ConcreateHandler1();
        Handler handler2 = new ConcreateHandler2();
        Handler handler3 = new ConcreateHandler3();

        //設定處理順序
        handler1.setNextHandler(handler2);
        handler2.setNextHandler(handler3);

        //提交請求,返回結果
        Response response = handler1.handlerMessage(new Request());
    }
}
ChainOfResponsibility的優點
  • 將請求與處理分開,請求者可以不用知道是誰處理的請求,處理者可以不用知道請求者的詳細細節

  • 遮蔽了請求的處理過程,可以不用去操心我的請求應該發給哪個處理者,只要把它扔給第一個處理者,讓它自己去判斷和傳遞

參考

《設計模式之禪》