責任鏈模式 旨在 解耦請求發送者與接收者。多個處理者組成鏈條,請求沿鏈傳遞,直到某處理者處理為止。
GoF 定義:使多個對象都有機會處理請求,從而避免發送者和接收者耦合。將對象連成鏈,沿鏈傳遞請求,直到有對象處理它。
| 角色 | 職責 |
|---|---|
| 抽象處理者 | 定義處理請求介面;可選:定義後繼者引用與鏈接邏輯 |
| 具體處理者 | 實現處理邏輯;若無法處理則委派給後繼者 |
| 維度 | 純粹模式 | 不純粹模式 |
|---|---|---|
| 處理者行為 | 二選一:完全處理 或 轉發下家 | 可部分處理後轉發;可全部嘗試處理 |
| 請求必被處理 | 是 | 否 (可無果而終) |
| 典型場景 | 嚴格分級審批、過濾器鏈 | 日誌記錄、多策略嘗試、事件廣播 |
實務建議:不要為符合教科書定義而強行純粹。降低耦合、提高復用、適應變化 才是衡量標準。「管它黑貓白貓,抓住老鼠就是好貓。」
系統需生成員工工號、檔案代號等,規則包含變動元素:年份、月份、日期、流水號。初期硬編碼,後期需擴展新元素。
public String generateCode(String rule) {
String result = rule;
result = result.replace("{YYYY}", currentYear());
result = result.replace("{MM}", currentMonth());
result = result.replace("{DD}", currentDay());
result = result.replace("{SEQ}", nextSequence());
return result;
}
問題:違反開閉原則,新增元素需修改核心邏輯。
public interface CodeAutoParse {
String[] generateCode(String moduleCode, int number, String rule, String[] target) throws BaseException;
}
public class DateAutoParse implements CodeAutoParse {
private final Calendar currentDate = Calendar.getInstance();
private CodeAutoParse nextParser; // Spring 注入
public void setNextParser(CodeAutoParse nextParser) {
this.nextParser = nextParser;
}
@Override
public String[] generateCode(String moduleCode, int number, String rule, String[] target) throws BaseException {
// 1. 解析規則中的日期佔位符
// 2. 更新 target 陣列
// ...
// 3. 委派下一個處理者 (不純粹模式:無論是否處理都傳遞)
if (nextParser != null) {
return nextParser.generateCode(moduleCode, number, rule, target);
}
return target;
}
}
<bean id="dateParser" class="com.example.DateAutoParse">
<property name="nextParser" ref="sequenceParser"/>
</bean>
<bean id="sequenceParser" class="com.example.SequenceAutoParse">
<property name="nextParser" ref="customFieldParser"/>
</bean>
<bean id="customFieldParser" class="com.example.CustomFieldAutoParse">
<property name="nextParser" ref="null"/> <!-- 鏈尾 -->
</bean>
新增處理者只需:實現介面 + 修改 Spring 配置,零修改現有代碼。
@Autowired
private CodeAutoParse firstParser; // 注入鏈頭
public String[] generate(String moduleCode, int number, String rule) {
return firstParser.generateCode(moduleCode, number, rule, new String[number]);
}
@Component
public class PriorityChainBuilder implements InitializingBean {
@Autowired
private List parsers; // 所有處理者
private CodeAutoParse head;
@Override
public void afterPropertiesSet() {
parsers.sort(Comparator.comparingInt(CodeAutoParse::getPriority));
for (int i = 0; i < parsers.size() - 1; i++) {
parsers.get(i).setNextParser(parsers.get(i + 1));
}
head = parsers.get(0);
}
public CodeAutoParse getHead() { return head; }
}
public class ConditionalParser implements CodeAutoParse {
private final Predicate condition;
private final CodeAutoParse delegate;
@Override
public String[] generateCode(...) {
if (condition.test(rule)) {
return delegate.generateCode(...);
}
return nextParser != null ? nextParser.generateCode(...) : target;
}
}
CircuitBreaker 防止級聯失效| 風險 | 對策 |
|---|---|
| 鏈路過長導致延遲 | 控制處理者數量;關鍵路徑避免深層鏈路 |
| 循環引用 (A→B→A) | 啟動時檢測;Spring 循環依賴檢查 |
| 執行緒安全 (共享狀態) | 處理者設計為無狀態;必要時 ThreadLocal |
| 除錯困難 | 鏈路執行日誌記錄處理者進入/退出/耗時 |
責任鏈模式通過 介面統一 + 鏈路外部化配置,實現了處理邏輯的模組化、動態組合與零侵入擴展。核心價值在於 「誰處理、按什麼順序、能否動態調整」 這三個決策從業務代碼中剝離。實務中採用不純粹模式、Spring 組裝鏈路、引入優先級/條件/熔斷機制,是企業級應用的成熟做法。