行為型設計模式之責任鏈模式
責任鏈模式介紹
責任鏈模式是一種鏈式結構,就是由一個個節點首尾相接串起來的結構,具有很好的靈活性,將每一個節點看作是一個物件,每一個物件擁有不同的處理邏輯,將一個請求從鏈式的首端發出,沿著鏈的路徑依此傳遞每一個節點物件,直到有物件處理這個請求為止,我們將這樣一種模式稱為責任鏈模式。
責任鏈模式的定義
使多個物件都有機會處理請求,從而避免了請求的傳送者和接受者之間的耦合關係。將這些物件連成一條鏈,並沿著這條鏈傳遞該請求,直到有物件處理它為止。
責任鏈模式的使用場景
(1)多個物件可以處理同一請求,但具體哪個物件處理則是在執行時動態決定
(2)在請求者不明確的情況下向多個物件中的一個提交一個請求
(3)需要動態指定一組物件的處理請求
責任鏈模式的類圖
角色介紹:
- AbstractHandler - 抽象處理者角色,宣告一個請求處理的方法(handle())、一個獲得處理級別的方法(getHandlerLever())和封裝了一個對具體的處理轉發邏輯實現的方法(handleRequest()),並在其中保持對下一個處理節點的AbstractHandler物件的引用(nextHandler)
- ConcreteHandler1、2 - 具體處理者角色,對請求進行處理,如果不能處理就將請求轉發給下一個節點上的處理物件
- AbstractRequest - 抽象的請求類,裡面聲明瞭一個獲得請求內容的方法(getContent())和一個獲得請求處理級別的方法(getRequestLever())
- ConcreteRequest - 具體的請求類
責任鏈模式的簡單實現
在一個公司中,員工拿到了一份合同,需要上級的簽名,於是員工就把合同給組長,但是組長沒有許可權簽名,於是組長就把合同給經理,但是經理也沒有足夠的許可權簽名,於是經理就把合同給老闆,老闆二話不說就把合同給簽了。上面的例子就是責任鏈模式,員工是請求的發起者,處於鏈的底端,而老闆是處於鏈條頂端的類,員工發起請求後,請求經過層層轉發,直至請求被處理,員工只是和組長髮生了關聯,後面合同被誰處理,員工並不知道,也並不關心,他在乎的是合同簽名的結果,責任鏈模式很好的將請求的發起者與處理者解耦,下面用程式碼來模擬。
抽象的員工,即AbstractHandler角色
public abstract class Staff {
protected Staff nextHandler;//上一級領導處理者
//處理轉發的邏輯
public final void handleRequest(Contract contract){
if(contract.getContractLever() < getHandlerLever()){
handle(contract);
}else {
if(nextHandler != null){
nextHandler.handleRequest(contract);
}
}
}
public abstract int getHandlerLever();//自身能處理請求的級別
public abstract void handle(Contract contract);//具體的處理過程
}
在這個抽象的處理者中,一是定義了兩個介面來確定一個Staff應有的行為和屬性,二是封裝了一個處理請求的邏輯轉發方法,確定當前Staff是否有足夠的級別來處理當前合同,如果沒有,就把合同轉發給上一級Staff,接下來是各個實現類。
組長,即ConcreteHandler角色
public class CroupStaff extends Staff {
@Override
public int getHandlerLever() {
return 1;
}
@Override
public void handle(Contract contract) {
System.out.println("組長簽名了合同!");
}
}
經理,即ConcreteHandler角色
public class ManagerStaff extends Staff {
@Override
public int getHandlerLever() {
return 2;
}
@Override
public void handle(Contract contract) {
System.out.println("經理簽名了合同!");
}
}
老闆,即ConcreteHandler角色
public class BossStaff extends Staff {
@Override
public int getHandlerLever() {
return 3;
}
@Override
public void handle(Contract contract) {
System.out.println("老闆簽名了合同!");
}
}
接下來看一看請求,就是合同
抽象的合同類,即AbstractRequest角色
public abstract class Contract {
public abstract String getContext();//獲得合同具體內容
public abstract int getContractLever();//獲得合同處理級別
}
具體的合同類,即ConcreteRequest角色
public class ConcreteContract extends Contract {
@Override
public String getContext() {
return "這是一份關於房產合作的合同";
}
@Override
public int getContractLever() {
return 3;
}
}
最後員工從組長髮起請求
請求發起者,員工
public class Employee {
public static void main(String[] args){
//構造各個節點物件
GroupStaff groupStaff = new GroupStaff();
ManagerStaff managerStaff = new ManagerStaff();
BossStaff bossStaff = new BossStaff();
//構成一條鏈
groupStaff.nextHandler = managerStaff;
managerStaff.nextHandler = bossStaff;
//發起請求
Contract contract = new ConcreteContract();
groupStaff.handleRequest(contract);
}
}
輸出結果
老闆簽名了合同!
其實這裡也可以直接繞過組長和經理,直接找老闆簽名,這也是責任鏈模式的靈活性,請求的發起可以從任意節點發起,同時也可以改變責任鏈模式內部的傳遞規則,如直接找老闆簽名。
總結
對於責任鏈模式中的節點,有兩個行為,一是處理請求,二是將請求轉發給下一個節點,不允許某個節點處理者處理了請求後又把節點轉發給下一個節點。對於責任鏈中的請求,只有倆個結果,一個是被某個節點處理,一個是所有物件均沒有處理。
優點:
請求者和處理者關係解耦
缺點:
對鏈中節點的遍歷,如果節點太多,會影響效能