委派與介面都能實現「行為參數化」與「多態」,但設計意圖、適用場景與底層機制截然不同。許多開發者在「該用委派還是介面?」猶豫不決。本文從契約觀點、輸入/輸出視角、演算法重用、耦合度五大維度深度對比,給出明確選型指南。
| 維度 | 委派 | 介面 |
|---|---|---|
| 本質 | **型別安全的函數指標** (單一方法簽名) | **契約** (多成員:方法、屬性、事件、索引子) |
| 實作主體 | **方法** (靜態、實例、匿名、Lambda) | **類別/結構** (需實作所有成員) |
| 狀態 | 無狀態 (透過閉包捕獲外部變數) | 有狀態 (類別欄位、屬性) |
| 多播 | 原生支援 (`+=` 串聯多個方法) | 不支援 (單一實作) |
| 協變/逆變 | 泛型委派支援 (`in`/`out`) | 泛型介面支援 (`in`/`out`) |
| 適用粒度 | **單一行為/演算法插槽** | **完整能力契約/角色** |
委派簽名 `delegate TResult Func
介面同理:`IEnumerable
// 介面逆變:一個比較器處理所有衍生類
interface IComparer { int Compare(T x, T y); }
class EntityComparer : IComparer { ... }
IComparer cmp = new EntityComparer(); // 逆變指派 OK
// 委派逆變:一個處理邏輯應用於所有衍生類
Action process = e => Console.WriteLine(e.Id);
Action processDerived = process; // 逆變指派 OK
processDerived(new DerivedEntity());
**結論**:逆變讓「為基類寫一次演算法,自動適用所有衍生類」成為型別安全現實,這是介面與委派共享的核心價值。
| 場景 | 推薦 | 理由 |
|---|---|---|
| 單一簡單回調 (比較、轉換、過濾、回呼) | **委派 / Func / Action** | 輕量、內聯 Lambda、支援多播、無需建立類別 |
| 多個相關操作組成的能力 (Repository、Serializer、Plugin) | **介面** | 語意完整、可攜帶狀態、支援 DI 容器、版本演進友善 |
| 事件發布-訂閱 | **事件 (基於委派)** | 語言內建模式、多播、標準化 EventHandler |
| 策略模式:執行時切換演算法 | **委派** (簡單) / **介面** (複雜策略需狀態/多方法) | 委派即輕量策略;介面支援策略內部狀態與多階段操作 |
| 需在類別圖中表達領域概念 | **介面** | 介面是公開契約,文檔化領域模型 |
| LINQ / 函數式管道 | **委派 / Lambda / 運算式樹** | 標準查詢運算子全部接受 Func/Expression |
委派 = **行為參數化** 的輕量工具,核心是「方法即資料」;介面 = **能力契約** 的標準化定義,核心是「類別即角色」。掌握 **in/out 直覺**、**契約履約者差異**、**演算法重用本質**,即可在任何情境下果斷選型,寫出既靈活又清晰的架構。