一、問題引入:
看一些開源項目源碼的時候,經常看到如下的結構設計:
我表示很費解。
二、問題分析:
為了分析問題,我寫了幾個測試的類和接口,如下:
接口:
public interface A { string Test1(); void Test2(); }
抽象類:
public abstract class B :A{ #region A 成員 public virtual string Test1() { Console.WriteLine("abstract B Test1"); return "B Test1"; } public virtual void Test2() { Console.WriteLine("abstract B Test2"); } #endregion }
同時繼承抽象類和實現接口的具體類:
public class C :B,A{ }
只繼承抽象類的具體類:
public class D :B{ }
測試也下各種用法:
A a1 = new C(); A a2 = new D(); B b1 = new C(); B b2 = new D(); a1.Test1(); a2.Test1(); Console.WriteLine(a1.GetType().GetInterfaces()[0]); Console.WriteLine(a2.GetType().GetInterfaces()[0]); Console.WriteLine(a1.GetType().BaseType); Console.WriteLine(a2.GetType().BaseType); Console.WriteLine("-----------------------------------------------"); Console.WriteLine(b1.GetType().GetInterfaces()[0]); Console.WriteLine(b2.GetType().GetInterfaces()[0]); Console.WriteLine(b1.GetType().BaseType); Console.WriteLine(b2.GetType().BaseType);
結果如下:
也就是這兩個具體類從表面上(運行結果)看沒有什么不同。
我仔細的查看了一下他們的IL代碼:
.class public auto ansi beforefieldinit D extends FMS_Refacting.interfaceAndabsctract.B { .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { .maxstack 8 L_0000: ldarg.0 L_0001: call instance void FMS_Refacting.interfaceAndabsctract.B::.ctor() L_0006: ret } }
.class public auto ansi beforefieldinit C extends FMS_Refacting.interfaceAndabsctract.B
implements FMS_Refacting.interfaceAndabsctract.A
{ .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { .maxstack 8 L_0000: ldarg.0 L_0001: call instance void FMS_Refacting.interfaceAndabsctract.B::.ctor() L_0006: ret } }
唯一的不同就是紅色部分標出。但這不會影響什么,因為根據繼承的定義,D是通過B來implements了A的,這種傳遞性和上面的沒有什么區別。所以從這里看也沒什么不同。
也就是說,這個兩種形式是一樣的!!!
我們知道:
接口:是包含一組虛方法的抽象類型,其中每一種方法都有其名稱、參數和返回值。接口方法不能包含任何實現,CLR允許接口可以包含事件、屬性、索引器、靜態方法、靜態字段、靜態構造函數以及常數。但是注意:C#中不能包含任何靜態成員。一個類可以實現多個接口,當一個類繼承某個接口時,它不僅要實現該接口定義的所有方法,還要實現該接口從其他接口中繼承的所有方法。
抽象類:提供多個派生類共享基類的公共定義,它既可以提供抽象方法,也可以提供非抽象方法。抽象類不能實例化,必須通過繼承由派生類實現其抽象方法,因此對抽象類不能使用new關鍵字,也不能被密封。如果派生類沒有實現所有的抽象方法,則該派生類也必須聲明為抽象類。另外,實現抽象方法由override方法來實現。
抽象類和接口比起來,有一個好處,就是某些函數可以實現具體的方法,而並不一定是聲明抽象的方法,而接口只能聲明抽象方法(並且強制子類實現),所以用一個抽象類來實現某個接口可以實現一些通用的方法,而這些具體實現的方法里還可以調用抽象方法,所以減少了子類中的重復代碼。
所以,D的繼承形式我覺着是比較常用的,但是為什么又出現C繼承形式了呢?我的猜想:
- 1、應該是框架上的需要便於擴展?
- 2、與設計模式有關?
- 3、美觀?
三、最后
我還是不能確定為什么要這么設計,有什么特殊的原因是我沒有想到的么?如果你知道請告訴我,我也會一直的尋找原因。不勝感激。