C#會重蹈覆轍嗎?系列之3:事件背後的臃腫設計哲學
今天來談談C#語言中事件的設計問題——這是除了效能問題之外,C#語言設計哲學中另外一個嚴重的問題——不必要的臃腫。C#事件總共存在以下4類問題:
1. C#事件沒有抽象性
事件並非物件的基本元素,並不反映物件的關鍵抽象。欄位反映物件狀態,方法反映物件行為,事件反映什麼?一個觀察-通知的關係結構嗎?
2. C#事件沒有通用性
絕大多數物件沒有事件的設計需求,不會實現事件。
3. C#事件的實現效能比較低下
a.C#事件的背後是一個委託連結串列(單鏈表),單鏈表的遍歷呼叫效能遠低於陣列連結串列(List<T>)
b.C#事件預設實現會產生一個委託欄位例項,支援不用的委託欄位例項是一個性能負擔(參見WPF/SL裡面的路由事件的改造設計)
4. C#事件沒有必要性——這一條是C#事件最大的問題,也是本文的重點
事件只是觀察者設計模式的變體。其完全可以用介面來實現。
將所謂常用的設計模式變成語言構造的一部分,是C#設計思想裡面又一個的嚴重錯誤(第一個嚴重錯誤是為了所謂的功能,而不管不問效能成本,在前文《C#會重蹈覆轍嗎?系列之2:反射及元資料的效能問題》中對此有詳述)。
C#中類似的例子還有:使用foreach和yield支援迭代器模式,使用using支援Dispose設計模式——我就在這裡一併批評了,不再另外撰文了。
如果可以在C#語言中內建Observer模式,內建Iterator模式, 內建Dispose模式,那麼要不要把Adapter模式也變成C#語言的一部分?要不要把Proxy模式也變成C#語言的一部分?Bridge呢?Composite呢?Strategy呢?.....幾百種模式是否都要變成C#語言的一部分???...
另外,在語言中內建設計模式,會使得該模式失去實現上的靈活性、或者損傷效能(比如C#事件就限定了觀察者模式必須使用委託來完成事件呼叫,使用委託連結串列來表達觀察者的物件集合,這種限制使得設計模式失去了其實現上的靈活性)
使用程式庫來支援設計模式是程式語言的正道,將模式整合為語言的一部分來耍cool,最後的結果是這個語言越來越臃腫,越來越龐大。希望C#設計師們在這條道路上止步。