【所見即所得】抽象類、接口的一點費解


 

 

一、問題引入:

看一些開源項目源碼的時候,經常看到如下的結構設計:

 

我表示很費解。

image

二、問題分析:

為了分析問題,我寫了幾個測試的類和接口,如下:

接口:

	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);

 

結果如下:

image

也就是這兩個具體類從表面上(運行結果)看沒有什么不同。

 

我仔細的查看了一下他們的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、美觀?

三、最后

我還是不能確定為什么要這么設計,有什么特殊的原因是我沒有想到的么?如果你知道請告訴我,我也會一直的尋找原因。不勝感激。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM