責任鏈模式將請求發送者與多個接收者解耦,請求沿鏈路傳遞直到被處理。本文以「多級請假審批」為例,展示如何將組長/部門主管/總經理封裝為獨立處理節點,動態組裝審批鏈,新增角色零修改核心代碼。
nextHandler 引用// 請求對象
class LeaveRequest {
private String applicant;
private int days;
private String reason;
// 構造器、getter/setter 省略
}
// 抽象處理者
abstract class Approver {
protected String name;
protected Approver nextApprover;
public Approver(String name) { this.name = name; }
public void setNext(Approver next) { this.nextApprover = next; }
public abstract void handle(LeaveRequest request);
}
// 具體處理者:組長(<3天)
class GroupLeader extends Approver {
public GroupLeader(String name) { super(name); }
public void handle(LeaveRequest req) {
if (req.getDays() < 3) {
printApproved(req, "組長");
} else {
System.out.println(name + "(組長)權限不足,轉交上級");
if (nextApprover != null) nextApprover.handle(req);
}
}
}
// 具體處理者:部門主管(<10天)
class DeptManager extends Approver {
public DeptManager(String name) { super(name); }
public void handle(LeaveRequest req) {
if (req.getDays() < 10) {
printApproved(req, "部門主管");
} else {
System.out.println(name + "(主管)權限不足,轉交上級");
if (nextApprover != null) nextApprover.handle(req);
}
}
}
// 具體處理者:總經理(<30天)
class GeneralManager extends Approver {
public GeneralManager(String name) { super(name); }
public void handle(LeaveRequest req) {
if (req.getDays() < 30) {
printApproved(req, "總經理");
} else {
printRejected(req, "總經理");
}
}
}
// 通用打印方法
void printApproved(LeaveRequest req, String role) {
System.out.println("===== 審批通過 =====");
System.out.println("申請人:" + req.getApplicant() + " | 天數:" + req.getDays() + " | 事由:" + req.getReason());
System.out.println("審批人:" + role + "(通過)");
}
void printRejected(LeaveRequest req, String role) {
System.out.println("===== 審批駁回 =====");
System.out.println("申請人:" + req.getApplicant() + " | 天數:" + req.getDays() + " | 事由:" + req.getReason());
System.out.println("審批人:" + role + "(駁回:超過權限上限)");
}
// 客戶端:動態組裝鏈路
public class Demo {
public static void main(String[] args) {
Approver leader = new GroupLeader("張三");
Approver manager = new DeptManager("李四");
Approver gm = new GeneralManager("王五");
// 組裝鏈路:組長 → 主管 → 總經理
leader.setNext(manager);
manager.setNext(gm);
// 測試不同天數
leader.handle(new LeaveRequest("小王", 2, "感冒")); // 組長通過
leader.handle(new LeaveRequest("小李", 5, "結婚")); // 主管通過
leader.handle(new LeaveRequest("小張", 15, "產假")); // 總經理通過
leader.handle(new LeaveRequest("小趙", 35, "環遊世界")); // 總經理駁回
}
}
| 傳統 if-else | 責任鏈模式 |
|---|---|
| 審批邏輯集中在一個巨大方法中 | 每個角色邏輯獨立封裝在單獨類中 |
| 新增角色需修改核心方法(違反開閉原則) | 新增角色只需新建類並接入鏈路 |
| 順序調整需修改代碼邏輯 | 僅調整 setNext 組裝順序 |
| 難以單元測試單個角色邏輯 | 每個處理者可獨立測試 |
| 職責邊界模糊 | 單一職責原則,邊界清晰 |
FilterChain.doFilter 標準責任鏈HandlerInterceptor 鏈式調用生產環境建議將鏈路組裝外部化配置:
# application.yml
approval-chain:
- com.approval.GroupLeader
- com.approval.DeptManager
- com.approval.GeneralManager
// Spring 啟動時按順序自動注入構建鏈路
@Component
public class ApprovalChainBuilder {
@Autowired List<Approver> approvers;
public Approver build() {
for (int i = 0; i < approvers.size() - 1; i++) {
approvers.get(i).setNext(approvers.get(i + 1));
}
return approvers.get(0);
}
}
責任鏈模式是流程型業務建模的利器,善用它能讓複雜審批、校驗、過濾邏輯清晰可控。