1. 程式人生 > >C#會重蹈覆轍嗎?系列之3:事件背後的臃腫設計哲學

C#會重蹈覆轍嗎?系列之3:事件背後的臃腫設計哲學

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

今天來談談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#設計師們在這條道路上止步。