翻了一半,到某些地方實在是看不下去了,鑒於這本書的名氣和傳說中的銷售量,這些地方拿出來給大家討論討論,對看了這本書而又沒發現這些東西的安達應該是有益的.
條款19:Prefer Defining and Implementing Interfaces to Inheritance。該條款教導我們,盡量定義並實現介面,而不是使用繼承。
實際上,抽象類別具有一些介面不可能提供的特點。
1、介面只是提供了實作類別提供的行為,而沒有提供這些行為的規範。如:一個數據機介面包括:撥號、發送資料、接收資料、掛斷這些行為,但是並沒有也沒辦法定義說發送資料之前,必須得先撥號,且撥號必須成功這樣的規範;但是抽象類別不同,它可以定義它們。
2、在抽象類別中增加一項功能,它的衍生類別就自動擁有了這些功能;這東西顯然通過介面實現不了——在介面中增加一向功能的後果是所有的實作類別都得重寫,並重新編譯。
在實際項目中,碰到過這種讓人非常頭痛的情況。所以一般做法是提供介面,然後提供一個實現了這個介面的抽象類別。衍生類別一般情況下是從抽象類別派生,而不是直接去實現介面。
OK,現在我們再來看<Effective C#>中提到的證明使用介面而不使用抽象類別的反例:
public void PrintCollection( IEnumerable collection )
{
foreach( object o in collection )
Console.WriteLine( "Collection contains {0}",
o.ToString( ) );
}
public void PrintCollection( CollectionBase collection )
{
foreach( object o in collection )
Console.WriteLine( "Collection contains {0}",
o.ToString( ) );
}
書裡面說了
“The second method is far less reusable. It cannot be used with Arrays, ArrayLists, DataTables, Hashtables, ImageLists, or many other collection classes. Coding the method using interfaces as its parameter types is far more generic and far easier to reuse.”大體意思是第二個方法可用性很差勁,它不能使用諸如:Arrays、ArrayLists、DataTables等等,使用第一種使用介面做參數方法就很好,用起來很方便。
現在的問題是:誰會這麼寫代碼呢?作為一個方法的參數,它可能會有一些限制,比如上述的PrintCollection。對該方法的實現,唯一的限制是它得實現IEnumerable介面,只要入口參數實現了這個介面,方法就可以完成預定義的語義。第二種寫法擴大了限制的範圍,擺明了後果就是可用性降低。
定義一個方法的入口參數類型,一個很重要的原則就是:最小限制化。
該原則同樣適用於泛型類和泛型方法的定義。
它後面的例子犯的錯誤如出一轍。
吃飯時間到了,其他的忽悠稍後。^_^
-- 補充點東西,見文《補》