責任鏈模式又稱職責鏈模式,屬于行為型模式;在責任鏈模式里,很多物件由每一個物件對其下家的參考而連接起來形成一條鏈,請求在這個鏈上傳遞,直到鏈上的某一個物件決定處理此請求,發出這個請求的客戶端并不指導鏈上的哪一個物件最終處理這個請求,這使得系統可以在不影響客戶端的情況下動態地重新組織鏈和分配責任,
責任鏈模式減低了請求的發送端和接收端之間的耦合,使多個物件都有機會處理這個請求,一個鏈可以是一條線,一個樹,也可以是一個環,鏈的拓撲結構可以是單連通的或多連通的,責任鏈模式并不指定責任鏈的拓撲結構,但是責任鏈模式要求在同一個時間里,命令只可以被傳給一個下家(或被處理掉),而不可以傳給多于一個下家,
責任鏈模式存在以下兩種情況,
- 純的責任鏈模式:一個請求必須被某一個處理者物件所接收,且一個具體處理者對某個請求的處理只能采用以下兩種行為之一:自己處理(承擔責任);把責任推給下家處理,
- 不純的責任鏈模式:允許出現某一個具體處理者物件在承擔了請求的一部分責任后又將剩余的責任傳給下家的情況,且一個請求可以最終不被任何接收端物件所接收,
責任鏈模式的UML類圖如下:

如上圖可以看出,責任鏈模式涉及到抽象處理者角色、具體處理者角色、客戶類角色三種角色:
- 抽象處理者(Handler)角色:定義一個處理請求的介面,包含抽象處理方法和一個后繼連接,
- 具體處理者(Concrete Handler)角色:實作抽象處理者的處理方法,判斷能否處理本次請求,如果可以處理請求則處理,否則將該請求轉給它的后繼者,
- 客戶類(Client)角色:創建處理鏈,并向鏈頭的具體處理者物件提交請求,它不關心處理細節和請求的傳遞程序,
OA采購審批的例子
某學校的OA系統的采購審批專案要求:
如果金額小于等于5000,由教學主任審批
如果金額小于等于10000,由院長審批
如果金額小于等于30000,由副校長審批
如果金額超過30000以上,有校長審批
對于這樣的需求就可以使用責任鏈模式,其UML類圖如下:

請求:
package com.charon.responsibility;
/**
* @className: PurchaseRequest
* @description:
* @author: charon
* @create: 2022-04-10 22:45
*/
public class PurchaseRequest {
/**
* 請求編號
*/
private String id;
/**
* 金額
*/
private double price;
public PurchaseRequest(String id, double price) {
this.id = id;
this.price = price;
}
/**
* Gets the value of id
*
* @return the value of id
*/
public String getId() {
return id;
}
/**
* Gets the value of price
*
* @return the value of price
*/
public double getPrice() {
return price;
}
}
抽象處理者:
package com.charon.responsibility;
/**
* @className: Approver
* @description: 抽象處理者
* @author: charon
* @create: 2022-04-10 22:43
*/
public abstract class Approver {
/**
* 下一個處理者
*/
private Approver Approver;
/**
* 姓名
*/
private String name;
public Approver(String name) {
this.name = name;
}
/**
* Sets the Approver
*
* @param approver Approver
*/
public void setApprover(Approver approver) {
Approver = approver;
}
/**
* Gets the value of Approver
*
* @return the value of Approver
*/
public com.charon.responsibility.Approver getApprover() {
return Approver;
}
/**
* Gets the value of name
*
* @return the value of name
*/
public String getName() {
return name;
}
/**
* 處理審批的方法
* @param request
*/
abstract void processRequest(PurchaseRequest request);
}
具體處理者:
package com.charon.responsibility;
/**
* @className: DepartmentApprover
* @description:
* @author: charon
* @create: 2022-04-10 22:52
*/
public class DepartmentApprover extends Approver{
public DepartmentApprover(String name) {
super(name);
}
@Override
void processRequest(PurchaseRequest request) {
if(request.getPrice() <= 5000){
System.out.println("請求編號為:" + request.getId() +" 被 " + this.getName() + "處理");
}else{
this.getApprover().processRequest(request);
}
}
}
package com.charon.responsibility;
/**
* @className: CollegeApprover
* @description:
* @author: charon
* @create: 2022-04-10 22:46
*/
public class CollageApprover extends Approver{
public CollageApprover(String name) {
super(name);
}
@Override
void processRequest(PurchaseRequest request) {
if(request.getPrice() > 5000 && request.getPrice() <= 10000){
System.out.println("請求編號為:" + request.getId() +" 被 " + this.getName() + "處理");
}else{
this.getApprover().processRequest(request);
}
}
}
package com.charon.responsibility;
/**
* @className: ViceSchoolApprover
* @description:
* @author: charon
* @create: 2022-04-10 22:53
*/
public class ViceSchoolApprover extends Approver{
public ViceSchoolApprover(String name) {
super(name);
}
@Override
void processRequest(PurchaseRequest request) {
if(request.getPrice() > 10000 && request.getPrice() <= 30000){
System.out.println("請求編號為:" + request.getId() +" 被 " + this.getName() + "處理");
}else{
this.getApprover().processRequest(request);
}
}
}
package com.charon.responsibility;
/**
* @className: SchoolMasterApprover
* @description:
* @author: charon
* @create: 2022-04-10 22:53
*/
public class SchoolMasterApprover extends Approver{
public SchoolMasterApprover(String name) {
super(name);
}
@Override
void processRequest(PurchaseRequest request) {
System.out.println("請求編號為:" + request.getId() +" 被 " + this.getName() + "處理");
}
}
客戶端測驗:
package com.charon.responsibility;
/**
* @className: Client
* @description:
* @author: charon
* @create: 2022-04-10 22:42
*/
public class Client {
public static void main(String[] args) {
PurchaseRequest request1 = new PurchaseRequest("1", 3500);
// 創建審批人
DepartmentApprover departmentApprover = new DepartmentApprover("張三主任");
CollageApprover collageApprover = new CollageApprover("李四院長");
ViceSchoolApprover viceSchoolApprover = new ViceSchoolApprover("王五副校長");
SchoolMasterApprover schoolMasterApprover = new SchoolMasterApprover("趙六校長");
// 設定好審批流程
departmentApprover.setApprover(collageApprover);
collageApprover.setApprover(viceSchoolApprover);
viceSchoolApprover.setApprover(schoolMasterApprover);
departmentApprover.processRequest(request1);
// viceSchoolApprover.processRequest(request1);
}
}
列印:
請求編號為:1 被 張三主任處理
責任鏈模式的主要優點如下:
- 降低了物件之間的耦合度,該模式使得一個物件無須知道到底是哪一個物件處理其請求以及鏈的結構,發送者和接收者也無須擁有對方的明確資訊,
- 增強了系統的可擴展性,可以根據需要增加新的請求處理類,滿足開閉原則,
- 增強了給物件指派職責的靈活性,當作業流程發生變化,可以動態地改變鏈內的成員或者調動它們的次序,也可動態地新增或者洗掉責任,
- 責任鏈簡化了物件之間的連接,每個物件只需保持一個指向其后繼者的參考,不需保持其他所有處理者的參考,這避免了使用眾多的 if 或者 if···else 陳述句,
- 責任分擔,每個類只需要處理自己該處理的作業,不該處理的傳遞給下一個物件完成,明確各類的責任范圍,符合類的單一職責原則,
責任鏈模式的主要缺點如下:
- 不能保證每個請求一定被處理,由于一個請求沒有明確的接收者,所以不能保證它一定會被處理,該請求可能一直傳到鏈的末端都得不到處理,
- 對比較長的職責鏈,請求的處理可能涉及多個處理物件,系統性能將受到一定影響,
- 職責鏈建立的合理性要靠客戶端來保證,增加了客戶端的復雜性,可能會由于職責鏈的錯誤設定而導致系統出錯,如可能會造成回圈呼叫,
模式的應用場景
- 多個物件可以處理一個請求,但具體由哪個物件處理該請求在運行時自動確定,
- 可動態指定一組物件處理請求,或添加新的處理者,
- 需要在不明確指定請求處理者的情況下,向多個處理者中的一個提交請求,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/457955.html
標籤:其他
