什麼是 Interception?#

Interception(攔截) 是指在協作物件之間攔截呼叫,以在不修改任何一方的情況下豐富或改變行為。這是 DI 三大維度之一,讓我們能夠在既有程式碼之上疊加額外功能。

Interception 之所以可能,正是因為我們遵循了 DI 的核心原則——依賴於 Abstraction、鬆耦合、Liskov Substitution Principle。

Figure 9.1: Interception 概念圖

Decorator Pattern:Interception 的核心機制#

Decorator Pattern 是實現 Interception 最直接的手段。Decorator 包裝了一個與自己實作相同 Abstraction 的物件,在呼叫前後加入額外邏輯:

Figure 9.2: Decorator Pattern 的一般結構

public class AuditingProductRepository : IProductRepository
{
    private readonly IProductRepository decoratee;
    private readonly IAuditTrail auditTrail;

    public AuditingProductRepository(
        IProductRepository decoratee,
        IAuditTrail auditTrail)
    {
        this.decoratee = decoratee;
        this.auditTrail = auditTrail;
    }

    public void Update(Product product)
    {
        auditTrail.Record($"Updating product {product.Id}");
        decoratee.Update(product);  // 委派給被裝飾的物件
    }
}

Decorator 的特性#

  • 實作與被裝飾物件相同的 Abstraction
  • 在建構函式中接收被裝飾物件(稱為 Decoratee
  • 在方法中委派 (Delegate) 給 Decoratee,並在前後加入邏輯
  • 可以鏈式串接(如同俄羅斯套娃)——多個 Decorator 層層包裹

Figure 9.3: 如同俄羅斯套娃,Decorator 層層包裹

// 在 Composition Root 中串接 Decorators
IProductRepository repository =
    new AuditingProductRepository(
        new CachingProductRepository(
            new SqlProductRepository(connectionString)),
        auditTrail);

橫切關注點 (Cross-Cutting Concerns)#

Interception 最大的價值在於處理橫切關注點——那些跨越多個模組、不屬於任何單一業務邏輯的功能。典型的橫切關注點包括:

  • Logging / Auditing(日誌與稽核)
  • Security / Authorization(安全與授權)
  • Transaction Management(交易管理)
  • Caching(快取)
  • Error Handling(錯誤處理)

Figure 9.6: 在架構圖中,Cross-Cutting Concerns 通常以跨越所有層的垂直區塊表示

實際範例#

Auditing Decorator#

稽核裝飾器在每次操作前後記錄稽核軌跡,完全不影響原有的業務邏輯:

  • 記錄誰在什麼時間做了什麼操作
  • 被裝飾的 Repository 完全不知道稽核的存在

Circuit Breaker#

斷路器模式追蹤對外部服務呼叫的失敗次數,當失敗超過閾值時自動「斷路」,避免持續呼叫已故障的服務:

Figure 9.7: Circuit Breaker 模式的簡化狀態轉換圖

  • 三種狀態:Closed(正常)→ Open(斷路)→ Half-Open(試探恢復)
  • 作為 Decorator 實作,包裹在實際的服務呼叫外層
  • 保護系統不因下游故障而連鎖崩潰

Exception Reporting#

例外回報裝飾器捕捉例外、記錄到監控系統,然後重新拋出:

public void Execute()
{
    try
    {
        decoratee.Execute();
    }
    catch (Exception ex)
    {
        reporter.Report(ex);  // 回報例外
        throw;                // 重新拋出,不吞掉例外
    }
}

Security / Authorization#

授權裝飾器在執行操作前檢查當前使用者是否具有足夠權限:

  • 權限不足時拋出例外或回傳錯誤
  • 將授權邏輯從業務邏輯中徹底分離

Decorator 在 Composition Root 中的組裝#

所有 Decorator 的組裝都發生在 Composition Root

// Composition Root
IProductRepository repository =
    new SecurityProductRepository(         // 最外層:授權檢查
        new AuditingProductRepository(     // 第二層:稽核記錄
            new CircuitBreakerRepository(  // 第三層:斷路器
                new SqlProductRepository(  // 核心實作
                    connectionString)),
            auditTrail),
        authService);

Decorator 的順序很重要。以上面的例子來說,授權檢查在最外層,確保未授權的操作不會觸發稽核記錄或實際的資料庫呼叫。

為什麼 DI 使 Interception 成為可能#

Interception 並非獨立的技術,它是 DI 原則的自然延伸:

  • 依賴於 Abstraction:Decorator 和 Decoratee 共享相同的 Abstraction
  • Liskov Substitution Principle:消費者無法區分原始實作和被裝飾過的版本
  • 鬆耦合:新增橫切關注點不需要修改任何既有程式碼
  • Composition Root:提供了集中組裝 Decorators 的位置

如果你的程式碼已經遵循 DI 原則,Interception 幾乎是免費獲得的能力。不需要額外的框架或工具,只需要在 Composition Root 中多包一層 Decorator。