1. 責任鏈模式的定義
責任鏈模式(Chain of Responsibility,簡稱 CoR,也叫職責鏈模式)是一種行為型設計模式,允許一個請求在一系列處理器(handlers)中傳遞。每個處理器可以選擇自己處理該請求,或者將其傳遞給下一個處理器。
一個大家比較熟悉的場景是找售后客服,通常是機器人客服先出來接待,然后在你的多次要求下轉給人工客服,如果是設備維修可能還需要轉到專業人員。這個場景就很適合應用責任鏈模式。總結一下就是這個模式適用于設計靈活、解耦的請求處理流水線。
2. 案例分析
2.1 需求
假設你被安排開發一個在線訂購系統。在用戶下單前,系統需要執行以下檢查:
- 驗證用戶身份(Authenticate)
- 若有需要,校驗管理員權限(Authorize)
- 清理和預處理輸入數據(Sanitize)
- 阻止重復失敗的請求(安全性)
- 如果有緩存則直接返回緩存結果
2.2 潛在問題
如果把所有這些檢查邏輯寫在一個很長的方法里,你會發現:
- 代碼變得冗長混亂,難維護;
- 添加或移除檢查邏輯很麻煩;
- 想在別處復用檢查邏輯會產生大量重復代碼。
2.3 基于責任鏈的解決方案
責任鏈模式將每個檢查邏輯封裝為獨立的處理器類(handler),在其中定義 handle()
方法來解決上述問題。
每個處理器可以自行決定:
- 是否處理當前請求;
- 是否將請求傳遞給下一個處理器。
最后將這些處理器串聯起來,形成一個處理流水線(chain)。
2.3.1 類定義
- Handler(處理器接口)
- BaseHandler(可選的抽象基類,提供鏈式調用邏輯)
- AuthHandler(認證處理器)
- SanitizeHandler(數據清理處理器)
- CacheHandler(緩存處理器)
每個處理器只需要知道下一個處理器,從而讓請求順序向下傳遞。
2.3.2 具體實現
步驟 1:定義處理器接口
interface Handler {void handle(Request request);
}
步驟 2:創建基礎處理器 BaseHandler(可選)
// BaseHandler 提供了公共邏輯,用于鏈接和轉發請求。
// 它實現了 Handler 接口。
abstract class BaseHandler implements Handler {// 保存下一個處理器的引用private Handler next;/*** 設置鏈中的下一個處理器。* 允許像這樣鏈式調用:auth.setNext(validation).setNext(logger);** @param next 下一個處理器* @return 返回傳入的處理器,用于鏈式調用*/public BaseHandler setNext(Handler next) {this.next = next;return (BaseHandler) next;}/*** 如果存在下一個處理器,則將請求轉發給它。** @param request 需要傳遞的請求對象*/protected void forward(Request request) {if (next != null) {// 委托給下一個處理器next.handle(request); }}
}
BaseHandler
是一個抽象類,不能直接使用,而是由具體的處理器(如AuthHandler
、ValidationHandler
等)繼承。
它封裝了職責鏈的核心邏輯:
setNext()
設置下一個處理器并返回它,以便鏈式調用;forward()
將請求傳遞給下一個處理器。具體處理器類只需要關注自身的
handle()
邏輯,執行完后調用forward(request)
即可。
步驟 3:定義請求對象
class Request {public String user;public boolean isAdmin;public boolean isValid = true;public boolean isCached;// ... 字段可以根據需要擴展
}
步驟 4:創建具體的處理器
// Handler 1: 檢查用戶是否已登錄
class AuthHandler extends BaseHandler {@Overridepublic void handle(Request request) {if (request.user == null) {System.out.println("[Auth] 用戶未認證,請求終止。");// 不再向下傳遞return; }System.out.println("[Auth] 用戶已認證。");// 交給下一個處理器forward(request); }
}// Handler 2: 管理員權限校驗
class AdminHandler extends BaseHandler {@Overridepublic void handle(Request request) {if (!request.isAdmin) {System.out.println("[Admin] 普通用戶,跳過管理員校驗。");} else {System.out.println("[Admin] 管理員驗證通過。");// 可執行管理員相關邏輯}forward(request);}
}// Handler 3: 數據清理
class SanitizeHandler extends BaseHandler {@Overridepublic void handle(Request request) {System.out.println("[Sanitize] 正在清理數據...");forward(request);}
}
步驟 5:組裝責任鏈
public class ChainApp {public static void main(String[] args) {Request request = new Request();request.user = "哈基米";request.isAdmin = true;Handler chain = new AuthHandler();chain.setNext(new AdminHandler()).setNext(new SanitizeHandler());chain.handle(request);}
}
2.3.3 執行流程
AuthHandler
驗證用戶;- 驗證通過后,將請求傳遞給
AdminHandler
; - 再傳遞到
SanitizeHandler
; - 如果某個處理器中斷了鏈條,后續處理器將不會執行。
3. 優缺點分析
3.1 優勢
- 處理器可復用,且易于單元測試;
- 可以在運行時動態配置責任鏈;
- 邏輯清晰,符合 單一職責原則(SRP);
- 處理順序不在處理器內部硬編碼,而是通過鏈式結構靈活定義。
3.2 缺點
- 如果鏈條覆蓋不全,可能存在請求未被處理的情況;
- 請求在長鏈路中傳遞時,跟蹤路徑可能較困難;
- 動態鏈條的調試可能比較復雜,需要設計合適的日志記錄方式。
4. 使用
4.1 常見應用場景
- 中間件管道(認證、校驗、日志記錄)
- GUI 事件處理(鼠標/鍵盤事件)
- 垃圾郵件過濾
- 文件格式識別
4.2 適用場景
當滿足以下條件時,可以考慮使用職責鏈模式:
- 有多個對象可以處理同一個請求;
- 需要解耦請求發送方和接收方;
- 需要復用或動態調整處理邏輯順序;
- 需要在某些條件下提前終止處理流程。
總結
**職責鏈模式的核心在于靈活性。**使得邏輯可以像流水線一樣串聯起來,每個處理器專注于一個小任務。合理的使用這種模式可以讓代碼邏輯更加清晰、便于測試和擴展,還能避免冗長的條件分支。