《紅樓夢》第七十五回描寫賈府擊鼓傳花:花在賈母、賈赦、賈政、寶玉、賈環間循環傳遞,鼓聲停時持花者飲酒。這正是責任鏈模式的完美隱喻:
// 1. 抽象處理者
abstract class Player {
private Player successor;
public Player(Player successor) { this.successor = successor; }
public void setSuccessor(Player successor) { this.successor = successor; }
public Player getSuccessor() { return successor; }
// 模板方法:定義處理流程骨架
public final void handle(int index) {
if (canHandle(index)) {
doHandle(index); // 自己處理
} else if (successor != null) {
successor.handle(index); // 轉發給下家
} else {
System.out.println("無人處理,程序結束");
}
}
protected abstract boolean canHandle(int index); // 判斷是否處理
protected abstract void doHandle(int index); // 具體處理邏輯
}
// 2. 具體處理者
class JiaMu extends Player {
public JiaMu(Player s) { super(s); }
protected boolean canHandle(int i) { return i == 1; }
protected void doHandle(int i) { System.out.println("賈母飲酒!"); }
}
class JiaShe extends Player { /* i==2 */ }
class JiaZheng extends Player { /* i==3 */ }
class JiaBaoYu extends Player { /* i==4 */ }
class JiaHuan extends Player { /* i==5 */ }
// 3. 客戶端組裝鏈
public class DrumBeater {
public static void main(String[] args) {
Player chain = new JiaMu(
new JiaShe(
new JiaZheng(
new JiaBaoYu(
new JiaHuan(null) // 尾節點
)
)
)
);
chain.handle(4); // 請求:第 4 號處理 → 寶玉飲酒
}
}
| 維度 | 純責任鏈 | 不純責任鏈 (常見) |
|---|---|---|
| 處理者行為 | 非處理即轉發,二選一 | 可部分處理後轉發,或不處理直接轉發 |
| 請求歸宿 | 必被某節點處理 | 可能無人處理(到達尾部仍未處理) |
| 典型案例 | 擊鼓傳花、審批流程 | AWT 1.0 事件浮升、DOM 事件冒泡、Servlet Filter 鏈 |
public boolean action(Event event, Object obj) {
if (event.target == btnOK) { doOKBtnAction(); }
else if (event.target == btnExit) { doExitBtnAction(); }
else { return super.action(event, obj); } // 向父容器傳播
return true; // true=停止傳播,false=繼續傳播
}
// HTML:
document.getElementById('b').onclick = function() {
alert('Button'); // 1. 目標階段
event.cancelBubble = true; // 阻止冒泡
};
document.getElementById('f').onclick = function() { alert('Form'); }; // 2. 冒泡階段
document.getElementById('d').onclick = function() { alert('Div'); }; // 3. 冒泡階段
document.onclick = function() { alert('Document'); }; // 4. 冒泡階段
cancelBubble = true 截斷鏈路event.stopPropagation()、addEventListener(type, handler, useCapture)captureEvents(Event.CLICK) 主動捕獲,releaseEvents() 釋放// 使用 Spring 管理節點順序,支援運行時動態調整
@Component
public class DrumGameChain {
@Autowired private List players; // 按 @Order 排序
public Player buildChain() {
Player head = null, prev = null;
for (Player p : players) {
if (head == null) head = p;
else prev.setSuccessor(p);
prev = p;
}
return head; // 返回鏈頭
}
}
// 配置順序
@Component @Order(1) public class JiaMu extends Player { ... }
@Component @Order(2) public class JiaShe extends Player { ... }
@Component @Order(3) public class JiaZheng extends Player { ... }
// 新增角色只需加 @Component @Order(n),零代碼修改
《墨子·迎敵祠》:「五步有伍長,十步有什長,百步有佰長,旁有大帥,中有大將」
handle() 骨架,子類實現 canHandle/doHandle責任鏈模式不僅是「鏈表」,更是「職責分發」的架構哲學。從《紅樓夢》擊鼓傳花到 AWT/DOM 事件模型,從墨子守城審批到現代 Servlet Filter、Spring Interceptor、Netty Pipeline——凡是「請求需經多級處理、處理者動態可變、發送者不關心具體處理者」的場景,皆為責任鏈用武之地。Java 開發者應掌握:Handler 接口設計、successor 引用管理、Spring 動態組裝鏈、FilterChain.doFilter() 標準協議。