請求的鏈式處理——責任鏈模式
什麽是責任鏈模式
職責鏈能夠是一條直線、一個環或者一個樹形結構,最常見的職責鏈是直線型。即沿著一條單向的鏈來傳遞請求。
鏈上的每個對象都是請求處理者。職責鏈模式能夠將請求的處理者組織成一條鏈。並讓請求沿著鏈傳遞,由鏈上的處理者對請求進行對應的處理,client無須關心請求的處理細節以及請求的傳遞,僅僅需將請求發送到鏈上就可以,實現請求發送者和請求處理者解耦。
職責鏈模式定義例如以下:
職責鏈模式(Chain of Responsibility Pattern):避免請求發送者與接收者耦合在一起,讓多個對象都有可能接收請求。將這些對象連接成一條鏈,並且沿著這條鏈傳遞請求,直到有對象處理它為止。職責鏈模式是一種對象行為型模式。
職責鏈模式結構的核心在於引入了一個抽象處理者。
職責鏈模式結構如圖所看到的:
在職責鏈模式結構圖中包括例如以下幾個角色:
● Handler(抽象處理者):它定義了一個處理請求的接口,一般設計為抽象類,因為不同的詳細處理者處理請求的方式不同,因此在當中定義了抽象請求處理方法。因為每個處理者的下家還是一個處理者,因此在抽象處理者中定義了一個抽象處理者類型的對象(如結構圖中的successor),作為其對下家的引用。
通過該引用。處理者能夠連成一條鏈。
● ConcreteHandler(詳細處理者):它是抽象處理者的子類。能夠處理用戶請求,在詳細處理者類中實現了抽象處理者中定義的抽象請求處理方法,在處理請求之前須要進行推斷,看是否有對應的處理權限。假設能夠處理請求就處理它,否則將請求轉發給後繼者;在詳細處理者中能夠訪問鏈中下一個對象,以便請求的轉發。
在職責鏈模式裏,非常多對象由每個對象對其下家的引用而連接起來形成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。
發出這個請求的client並不知道鏈上的哪一個對象終於處理這個請求。這使得系統能夠在不影響client的情況下動態地又一次組織鏈和分配責任。
職責鏈模式的核心在於抽象處理者類的設計,抽象處理者的典型代碼例如以下所看到的:
abstract class Handler {
//維持對下家的引用
protected Handler successor;
public void setSuccessor(Handler successor) {
this .successor=successor;
}
public abstract void handleRequest(String request);
}
上述代碼中。抽象處理者類定義了對下家的引用對象,以便將請求轉發給下家,該對象的訪問符可設為protected。在其子類中能夠使用。
在抽象處理者類中聲明了抽象的請求處理方法,詳細實現交由子類完畢。
詳細處理者是抽象處理者的子類,它具有兩大作用:第一是處理請求。不同的詳細處理者以不同的形式實現抽象請求處理方法handleRequest();第二是轉發請求,假設該請求超出了當前處理者類的權限,能夠將該請求轉發給下家。
詳細處理者類的典型代碼例如以下:
class ConcreteHandler extends Handler {
public void handleRequest(String request) {
if (請求滿足條件) {
//處理請求
}
else {
this.successor.handleRequest(request); //轉發請求
}
}
}
在詳細處理類中通過對請求進行推斷能夠做出對應的處理。
須要註意的是。職責鏈模式並不創建職責鏈,職責鏈的創建工作必須由系統的其它部分來完畢。通常是在使用該職責鏈的client中創建職責鏈。職責鏈模式減少了請求的發送端和接收端之間的耦合。使多個對象都有機會處理這個請求。
實戰案例
相信大家在公司中或多或少的都經歷過報銷。普通情況下在公司報銷會因報銷額度的不同而轉為不同人員進行審批。比如組長僅僅能審批1000元、主管僅僅能審批5000元。經理能審批10000元。10000元以上的僅僅能由老板親自審批了。
我們使用職責鏈模式來模擬 一下這個審批過程。
首先我們先聲明一個抽象的領導類。
public abstract class Leader {
// 上一級領導處理者
protected Leader nextHandler;
public final void handleRequest(int money) {
if (money <= limit()) {
handle(money);
} else {
if(null != nextHandler) {
nextHandler.handle(money);
}
}
}
/**
* 自身能批復的額度權限
* @return 額度
*/
public abstract int limit();
/**
* 處理報賬行為
* @param money 詳細金額
*/
public abstract void handle(int money);
}
在這個抽象的領導類中做了兩件事,一是定義了兩個抽象接口方法來確定一個領導者應有的行為和屬性,而是聲明了一個處理報賬請求的方法來確定當前領導是否有能力處理報賬請求,假設沒有權限。則將該請求轉發給上級領導處理。接下來是各個領導類的實現。
public class GroupLeader extends Leader {
@Override
public int limit() {
return 1000;
}
@Override
public void handle(int money) {
System.out.println("組長批復報銷 :" + money + "元");
}
}
public class Director extends Leader {
@Override
public int limit() {
return 5000;
}
@Override
public void handle(int money) {
System.out.println("主管批復報銷" + money + "元");
}
}
public class Manager extends Leader {
@Override
public int limit() {
return 10000;
}
@Override
public void handle(int money) {
System.out.println("經理批復報銷" + money + "元");
}
}
public class Boss extends Leader {
@Override
public int limit() {
return Integer.MAX_VALUE;
}
@Override
public void handle(int money) {
System.out.println("老板批復報銷" + money + "元");
}
}
我們在看看client是怎樣發起請求申請報銷的。
public static void main(String[] args) {
// 構造各個領導對象
GroupLeader groupLeader = new GroupLeader();
Director director = new Director();
Manager manager = new Manager();
Boss boss = new Boss();
// 設置上一級領導處理對象
groupLeader.nextHandler = director;
director.nextHandler = manager;
manager.nextHandler = boss;
// 發起報銷申請
groupLeader.handleRequest(10000);
}
首先我們須要構建各個領導對象,然後將每一級的上級設置好,這樣鏈式就形成了。最後我們申請報銷10000元。執行結果例如以下:
主管批復報銷10000元
純與不純的職責鏈模式
職責鏈模式可分為純的職責鏈模式和不純的職責鏈模式兩種:
(1) 純的職責鏈模式
一個純的職責鏈模式要求一個詳細處理者對象僅僅能在兩個行為中選擇一個:要麽承擔所有責任。要麽將責任推給下家,不同意出現某一個詳細處理者對象在承擔了一部分或所有責任後又將責任向下傳遞的情況。並且在純的職責鏈模式中,要求一個請求必須被某一個處理者對象所接收,不能出現某個請求未被不論什麽一個處理者對象處理的情況。在前面的採購單審批實例中應用的是純的職責鏈模式。
(2)不純的職責鏈模式
在一個不純的職責鏈模式中同意某個請求被一個詳細處理者部分處理後再向下傳遞,或者一個詳細處理者處理完某請求後其後繼處理者能夠繼續處理該請求,並且一個請求能夠終於不被不論什麽處理者對象所接收。
職責鏈模式總結
職責鏈模式通過建立一條鏈來組織請求的處理者,請求將沿著鏈進行傳遞。請求發送者無須知道請求在何時、何處以及怎樣被處理,實現了請求發送者與處理者的解耦。在軟件開發中,假設遇到有多個對象能夠處理同一請求時能夠應用職責鏈模式,比如在Web應用開發中創建一個過濾器(Filter)鏈來對請求數據進行過濾,在工作流系統中實現公文的分級審批等等,使用職責鏈模式能夠較好地解決此類問題。
1.主要長處
職責鏈模式的主要長處例如以下:
(1) 職責鏈模式使得一個對象無須知道是其它哪一個對象處理其請求,對象僅需知道該請求會被處理就可以,接收者和發送者都沒有對方的明白信息。且鏈中的對象不須要知道鏈的結構。由client負責鏈的創建,減少了系統的耦合度。
(2) 請求處理對象僅需維持一個指向其後繼者的引用。而不須要維持它對所有的候選處理者的引用,可簡化對象的相互連接。
(3) 在給對象分派職責時,職責鏈能夠給我們很多其它的靈活性,能夠通過在執行時對該鏈進行動態的添加或改動來添加或改變處理一個請求的職責。
(4) 在系統中添加一個新的詳細請求處理者時無須改動原有系統的代碼,僅僅須要在client又一次建鏈就可以。從這一點來看是符合“開閉原則”的。
2.主要缺點
職責鏈模式的主要缺點例如以下:
(1) 因為一個請求沒有明白的接收者。那麽就不能保證它一定會被處理。該請求可能一直到鏈的末端都得不到處理。一個請求也可能因職責鏈沒有被正確配置而得不到處理。
(2) 對於比較長的職責鏈,請求的處理可能涉及到多個處理對象,系統性能將受到一定影響,並且在進行代碼調試時不太方便。
(3) 假設建鏈不當。可能會造成循環調用,將導致系統陷入死循環。
3.適用場景
在下面情況下能夠考慮使用職責鏈模式:
(1) 有多個對象能夠處理同一個請求,詳細哪個對象處理該請求待執行時刻再確定,client僅僅需將請求提交到鏈上,而無須關心請求的處理對象是誰以及它是怎樣處理的。
(2) 在不明白指定接收者的情況下,向多個對象中的一個提交一個請求。
(3) 可動態指定一組對象處理請求。client能夠動態創建職責鏈來處理請求,還能夠改變鏈中處理者之間的先後次序。
請求的鏈式處理——責任鏈模式