責任鏈模式——ChainOfResponsibility
案例展示——ChainOfResponsibility怎麼用?
考慮這樣一個場景:現有一家工廠(大型綜合一體化工廠),從原料生產到成品出產都由這家工廠獨立完成。為了便於管理與提高效率,只能明確,工廠領導層決定將工廠一分為三:原料廠負責原料的生產和購買,零件製造廠負責零部件的製造,裝配廠負責裝配出廠。同時為了便於監管,督促各大工廠之間保質保量的完成任務,領導層委派很多監察者去各大工廠監察,每個監察者都有自己特定監察的工廠:原料廠監察者負責監察原料廠,零件製造廠監察者負責監察零件製造廠,裝配廠監察者負責監察裝配廠,每個人都各司其職。下面是類圖設計:
分析上面的類圖如下:
-
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類)
所以正確的處理請求應該是這樣的,首先,每個工廠應該提前知道監察者的身份,判斷自己能否接受監察,如果不能將其傳遞給下一個工廠。下面是類圖設計:
分析上面的類圖如下:
- 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的定義
定義: 使多個物件都有機會處理請求,從而避免了請求的傳送者和接受者之間的耦合關係。將這些物件連城一條鏈,並沿著這條鏈傳遞該請求,直到有物件處理它為止。下面是通用類圖:
責任鏈模式的核心: 由一條鏈去處理相似的請求,並在鏈中決定由誰來處理這個請求,同時返回相應的結果。
下面是通用程式碼:
//抽象處理者
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的優點
-
將請求與處理分開,請求者可以不用知道是誰處理的請求,處理者可以不用知道請求者的詳細細節
-
遮蔽了請求的處理過程,可以不用去操心我的請求應該發給哪個處理者,只要把它扔給第一個處理者,讓它自己去判斷和傳遞
參考
《設計模式之禪》