組件間依賴兩種基本模式:
介面 IoC 雖具編譯期檢查,但整合第三方元件需撰寫 Adapter 包裝,靈活性受限。委託 IoC 消除型別依賴,僅需簽名相容,更靈活。極致是 HTTP+XML/JSON 協議式整合,甚至跨語言,但失去編譯期保護。
委託是「中庸之道」:保留 IDE 提示與編譯器簽名檢查,又不產生組件依賴。
「走起來像鴨子、叫起來像鴨子,就當它是鴨子」。關注 物件能做什麼,而非繼承自誰。純粹實現:
object person = new Person(); // 未實作 IPerson
IPerson duck = Duck.Create(person); // 動態代理實作介面
Console.WriteLine($"{duck.Name} will be {duck.Age + 1} next year");
duck.Play("basketball");
C# 實現途徑:System.Reflection.Emit 動態生成實作目標介面的代理類別,攔截呼叫轉發至目標物件反射調用。Castle DynamicProxy 是成熟庫,極簡完成此功能。
string json = @"{ ""FirstName"": ""John"", ""Age"": 21 }";
dynamic person = CreateFromJson(json);
Console.WriteLine($"{person.FirstName} will be {person.Age + 1} next year");
person.Play("basketball"); // 編譯通過,執行期拋異常
dynamic 關閉編譯期型別檢查,全部轉為執行期反射調用。便利但 失去所有靜態保護,類似 HTTP+XML 協議模式。
// 概念碼:屬性/方法名動態,但型別靜態檢查
string firstName = person.Property("FirstName");
int age = person.Property("Age");
Func toJson = person.Method>("ToJson");
Action play = person.Method>("Play");
此模式在 C# 2.0 即可用 Dynamic 包裝類實現:
object jsonObj = CreateFromJson(...);
Dynamic person = new Dynamic(jsonObj);
string firstName = person.Property("FirstName");
保留動態名稱靈活性,同時享受屬性型別與方法簽名的編譯期檢查,將執行期錯誤降至最低。
下篇將實作 Dynamic 類別,敬請期待。