在C#中interface與abstract class的區別

来源:http://www.cnblogs.com/Mryang-blog-cn/archive/2017/04/03/Csharp_Interface_And_Abstract.html
-Advertisement-
Play Games

概念引入 ●什麼是介面? 介面是包含一組虛方法的抽象類型,其中每一種方法都有其名稱、參數和返回值。介面方法不能包含任何實現,CLR允許介面可以包含事件、屬性、索引 器、靜態方法、靜態欄位、靜態構造函數以及常數。但是註意:C#中不能包含任何靜態成員。一個類可以實現多個介面,當一個類繼承某個介面時,它不 ...


 1)在繼承抽象類時,必須覆蓋該類中的每一個抽象方法,而每個已實現的方法必須和抽象類中指定的方法一樣,接收相同數目和類型的參數,具有同樣的返回值,這一點與介面相同。
  2)當父類已有實際功能的方法時,該方法在子類中可以不必實現,直接引用的方法,子類也可以重寫該父類的方法(繼承的概念)。
  3)而實現 (implement)一個介面(interface)的時候,是一定要實現介面中所定義的所有方法,而不可遺漏任何一個。
  4)另外,抽象類不能產生對象的,但可以由它的實現類來聲明對象。


A. 兩者都是抽象類,都不能實例化。
B. interface實現類及abstrct class的子類都必須要實現已經聲明的抽象方法。2. 不同
A. interface需要實現,要用implements,而abstract class需要繼承,要用extends。
B. 一個類可以實現多個interface,但一個類只能繼承一個abstract class。
C. interface強調特定功能的實現,而abstract class強調所屬關係。
D. 儘管interface實現類及abstrct class的子類都必須要實現相應的抽象方法,但實現的形式不同。interface中的每一個方法都是抽象方法,都只是聲明的(declaration, 沒有方法體),實現類必須要實現。而abstract class的子類可以有選擇地實現。這個選擇有兩點含義:
一是Abastract class中並非所有的方法都是抽象的,只有那些冠有abstract的方法才是抽象的,子類必須實現。那些沒有abstract的方法,在Abstrct class中必須定義方法體。
二是abstract class的子類在繼承它時,對非抽象方法既可以直接繼承,也可以覆蓋;而對抽象方法,可以選擇實現,也可以通過再次聲明其方法為抽象的方式,無需實現,留給其子類來實現,但此類必須也聲明為抽象類。既是抽象類,當然也不能實例化。
E. abstract class是interface與Class的中介。
interface是完全抽象的,只能聲明方法,而且只能聲明pulic的方法,不能聲明private及protected的方法,不能定義方法體,也不能聲明實例變數。然而,interface卻可以聲明常量變數,並且在JDK中不難找出這種例子。但將常量變數放在interface中違背了其作為介面的作用而存在的宗旨,也混淆了interface與類的不同價值。如果的確需要,可以將其放在相應的abstract class或Class中。
abstract class在interface及Class中起到了承上啟下的作用。一方面,abstract class是抽象的,可以聲明抽象方法,以規範子類必須實現的功能;另一方面,它又可以定義預設的方法體,供子類直接使用或覆蓋。另外,它還可以定義自己的實例變數,以供子類通過繼承來使用。3. interface的應用場合
A. 類與類之前需要特定的介面進行協調,而不在乎其如何實現。
B. 作為能夠實現特定功能的標識存在,也可以是什麼介面方法都沒有的純粹標識。
C. 需要將一組類視為單一的類,而調用者只通過介面來與這組類發生聯繫。
D. 需要實現特定的多項功能,而這些功能之間可能完全沒有任何聯繫。4. abstract class的應用場合
一句話,在既需要統一的介面,又需要實例變數或預設的方法的情況下,就可以使用它。最常見的有:
A. 定義了一組介面,但又不想強迫每個實現類都必須實現所有的介面。可以用abstract class定義一組方法體,甚至可以是空方法體,然後由子類選擇自己所感興趣的方法來覆蓋。
B. 某些場合下,只靠純粹的介面不能滿足類與類之間的協調,還必需類中表示狀態的變數來區別不同的關係。abstract的中介作用可以很好地滿足這一點。
C. 規範了一組相互協調的方法,其中一些方法是共同的,與狀態無關的,可以共用的,無需子類分別實現;而另一些方法卻需要各個子類根據自己特定的狀態來實現特定的功能。



 概念引入

●什麼是介面?

介面是包含一組虛方法的抽象類型,其中每一種方法都有其名稱、參數和返回值。介面方法不能包含任何實現,CLR允許介面可以包含事件、屬性、索引 器、靜態方法、靜態欄位、靜態構造函數以及常數。但是註意:C#中不能包含任何靜態成員。一個類可以實現多個介面,當一個類繼承某個介面時,它不僅要實現 該介面定義的所有方法,還要實現該介面從其他介面中繼承的所有方法。

定義方法為:

以下為引用的內容:
public interface System.IComparable
{
    int CompareTo(object o);

public class TestCls: IComparable
{
    public TestCls()
    {
    }


    private int _value;
    public int Value
    {
        get { return _value; }
        set { _value = value; }
    }


   public int CompareTo(object o)
    {

        //使用as模式進行轉型判斷
        TestCls aCls = o as TestCls;
        if (aCls != null)
        {

        //實現抽象方法
        return _value.CompareTo(aCls._value);
        }
    }
}

●什麼是抽象類?

抽象類提供多個派生類共用基類的公共定義,它既可以提供抽象方法,也可以提供非抽象方法。抽象類不能實例化,必須通過繼承由派生類實現其抽象方法, 因此對抽象類不能使用new關鍵字,也不能被密封。如果派生類沒有實現所有的抽象方法,則該派生類也必須聲明為抽象類。另外,實現抽象方法由 overriding方法來實現。

定義方法為:

以下為引用的內容:
/// <summary>
/// 定義抽象類
/// </summary>
abstract public class Animal
{
    //定義靜態欄位
    static protected int _id; 
    //定義屬性
    public abstract static int Id
    {
        get;
        set;
    }


    //定義方法
    public abstract void Eat();

    //定義索引器
    public string this[int i]
    {
        get;
        set;
    } 
}

/// <summary>
/// 實現抽象類
/// </summary>
public class Dog: Animal
{
    public static override int Id
    {
        get {return _id;}
        set {_id = value;}
    }


    public override void Eat()
    {
        Console.Write("Dog Eats.")
    }
}

3. 相同點和不同點

3.1 相同點

●都不能被直接實例化,都可以通過繼承實現其抽象方法。 
●都是面向抽象編程的技術基礎,實現了諸多的設計模式。

3.2 不同點

●介面支持多繼承;抽象類不能實現多繼承。 
●介面只能定義抽象規則;抽象類既可以定義規則,還可能提供已實現的成員。 
●介面是一組行為規範;抽象類是一個不完全的類,著重族的概念。 
●介面可以用於支持回調;抽象類不能實現回調,因為繼承不支持。 
●介面只包含方法、屬性、索引器、事件的簽名,但不能定義欄位和包含實現的方法;抽象類可以定義欄位、屬性、包含有實現的方法。  
●介面可以作用於值類型和引用類型;抽象類只能作用於引用類型。例如,Struct就可以繼承介面,而不能繼承類。

通過相同與不同的比較,我們只能說介面和抽象類,各有所長,但無優略。在實際的編程實踐中,我們要視具體情況來酌情量才,但是以下的經驗和積累,或 許能給大家一些啟示,除了我的一些積累之外,很多都來源於經典,我相信經得起考驗。所以在規則與場合中,我們學習這些經典,最重要的是學以致用,當然我將 以一家之言博大家之笑,看官請繼續。

3.3 規則與場合

1.請記住,面向對象思想的一個最重要的原則就是:面向介面編程。 
2.藉助介面和抽象類,23個設計模式中的很多思想被巧妙的實現了,我認為其精髓簡單說來就是:面向抽象編程。 
3.抽象類應主要用於關係密切的對象,而介面最適合為不相關的類提供通用功能。 
4.介面著重於CAN-DO關係類型,而抽象類則偏重於IS-A式的關係; 
5.介面多定義對象的行為;抽象類多定義對象的屬性;  
6.介面定義可以使用public、protected、internal 和private修飾符,但是幾乎所有的介面都定義為public,原因就不必多說了。 
7.“介面不變”,是應該考慮的重要因素。所以,在由介面增加擴展時,應該增加新的介面,而不能更改現有介面。 
8.儘量將介面設計成功能單一的功能塊,以.NET Framework為例,IDisposable、IDisposable、IComparable、IEquatable、IEnumerable等都只包含一個公共方法。 
9.介面名稱前面的大寫字母“I”是一個約定,正如欄位名以下劃線開頭一樣,請堅持這些原則。 
10.在介面中,所有的方法都預設為public。  
11. 如果預計會出現版本問題,可以創建“抽象類”。例如,創建了狗(Dog)、雞(Chicken)和鴨(Duck),那麼應該考慮抽象出動物 (Animal)來應對以後可能出現風馬牛的事情。而向介面中添加新成員則會強制要求修改所有派生類,並重新編譯,所以版本式的問題最好以抽象類來實現。

12.從抽象類派生的非抽象類必須包括繼承的所有抽象方法和抽象訪問器的實實現。 
13.對抽象類不能使用new關鍵字,也不能被密封,原因是抽象類不能被實例化。 
14.在抽象方法聲明中不能使用 static 或 virtual 修飾符。

以上的規則,我就厚顏無恥的暫定為T14條吧,寫的這麼累,就當一時的獎賞吧。大家也可以互通有無,我將及時修訂。

4. 經典示例

4.1 絕對經典

.NET Framework是學習的最好資源,有意識的研究FCL是每個.NET程式員的必修課,關於介面和抽象類在FCL中的使用,我有以下的建議:

1.FCL對集合類使用了基於介面的設計,所以請關註System.Collections中關於介面的設計實現; 
2.FCL對數據流相關類使用了基於抽象類的設計,所以請關註System.IO.Stream類的抽象類設計機制。

4.2 別樣小菜

下麵的實例,因為是我的理解,因此給經典打上“相對”的記號,至於什麼時候晉升為“絕對”,就看我在.NET追求的路上,是否能夠一如既往的如此執 著,因此我將把相對重構到絕對為止(呵呵)。 本示例沒有闡述抽象類和介面在設計模式中的應用,因為那將是另一篇有討論價值的文本,本文著眼與概念和原則的把握,但是真正的應用來自於具體的需求規範。

設計結構如圖所示: 

1. 定義抽象類

以下為引用的內容:
public abstract class Animal
{
    protected string _name; 
    //聲明抽象屬性
    public abstract string Name
    {
        get;
    }

    //聲明抽象方法
    public abstract void Show();

    //實現一般方法
    public void MakeVoice()
    {
        Console.WriteLine("All animals can make voice!");
    }


2. 定義介面

以下為引用的內容:
public interface IAction
{
    //定義公共方法標簽
    void Move();
}

3. 實現抽象類和介面

以下為引用的內容:
public class Duck : Animal, IAction
{
    public Duck(string name)
    {
        _name = name;
    } 
    //重載抽象方法
    public override void Show()
    {
        Console.WriteLine(_name + " is showing for you.");
    }

    //重載抽象屬性
    public override string Name
    {
        get { return _name;}
    }

    //實現介面方法
    public void Move()
    {
        Console.WriteLine("Duck also can swim.");
    }

}

public class Dog : Animal, IAction
{
    public Dog(string name)
    {
        _name = name;
    }

    public override void Show()
    {
        Console.WriteLine(_name + " is showing for you.");
    }

    public override string Name
    {
        get { return _name; }
    }

    public void Move()
    {
        Console.WriteLine(_name + " also can run.");
    }


}

4. 客戶端實現

以下為引用的內容:

public class TestAnmial
{
    public static void Main(string [] args)
    {
        Animal duck = new Duck("Duck");
        duck.MakeVoice();
        duck.Show();

        Animal dog = new Dog("Dog");
        dog.MakeVoice();
        dog.Show();


        IAction dogAction = new Dog("A big dog");
        dogAction.Move();
    }


5. 他山之石

正所謂真理是大家看出來的,所以將園子里有創新性的觀點潛列於此,一是感謝大家的共用,二是完善一家之言的不足,希望能夠將領域形成知識,受用於我,受用於眾。


●[url=]dunai[/url]認為:抽象類是提取具體類的公因式,而介面是為了將一些不相關的類“雜湊”成一個共同的群體。至於他們在各個語言中的句法,語言細節並不是我關心的重點。 
●樺山澗的收藏也很不錯。 
●Artech認為:所代碼共用和可擴展性考慮,儘量使用Abstract Class。當然介面在其他方面的優勢,我認為也不可忽視。 
●shenfx認為:當在差異較大的對象間尋求功能上的共性時,使用介面;當在共性較多的對象間尋求功能上的差異時,使用抽象基類。

最後,MSDN的建議是:

●如果預計要創建組件的多個版本,則創建抽象類。抽象類提供簡單易行的方法來控制組件版本。通過更新基類,所有繼承類都隨更改自動更新。另一方面,介面一旦創建就不能更改。如果需要介面的新版本,必須創建一個全新的介面。 
●如果創建的功能將在大範圍的全異對象間使用,則使用介面。抽象類應主要用於關係密切的對象,而介面最適合為不相關的類提供通用功能。 
●如果要設計小而簡練的功能塊,則使用介面。如果要設計大的功能單元,則使用抽象類。 
●如果要在組件的所有實現間提供通用的已實現功能,則使用抽象類。抽象類允許部分實現類,而介面不包含任何成員的實現。

6. 結論

介面和抽象類,是論壇上、課堂間討論最多的話題之一,之所以將這個老話題拿出來再議,是因為從我的體會來說,深刻的理解這兩個面向對象的基本內容, 對於盤活面向對象的抽象化編程思想至關重要。本文基本概況了介面和抽象類的概念、異同和使用規則,從學習的觀點來看,我認為這些總結已經足以表達其核心。 但是,對於面向對象和軟體設計的深入理解,還是建立在不斷實踐的基礎上,Scott說自己每天堅持一個小時用來寫Demo,那麼我們是不是更應該勤於鍵盤 呢。對於介面和抽象類,請多用而知其然,多想而知其奧吧。









您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一步步打造一個簡單的 MVC 電商網站 - BooksStore(四) 本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore 《一步步打造一個簡單的 MVC 電商網站 - BooksStore(一)》(發佈時間:2017-03-3 ...
  • 開發工具:VS2010,MVC4.0,SQLSERVER2008 伺服器:Windows server 2012,IIS8,SQLSERVER2012 一、發佈後,每個頁面第一次打開都很卡,50秒或更長,第二次打開就很快了 估計原因:編譯速度慢,但在有VS環境的機器上發佈沒有這麼卡 解決辦法: 使用... ...
  • ElasticSearch NEST Client 操作Index var indexName="twitter"; var deleteIndexResponse = client.DeleteIndex(indexName); var createIndexResponse = client.C ...
  • 值類型:int double char bool decimal struct enum 值存儲在記憶體的棧上 引用類型: string 數組 自定義類 介面 委托 值存儲在堆中 值傳遞:把值類型作為參數傳遞,傳遞的是值本身 註:ref可以把值傳遞改變為引用傳遞 引用傳遞:把引用類型的值作為參數傳遞, ...
  • 設計模式(Design pattern):指的是一種大多數人反覆使用的代碼設計經驗。 作用:代碼復用、易讀性、保證代碼可靠性。 一、簡單工廠模式 用法:創建一個工廠類(命名習慣以Factiory結尾),一個靜態的帶參數(根據不同的參數返回不同的子類對象)的父類類型的方法。 public class ...
  • 記錄點點滴滴知識,為了更好的服務後來者! 一、為什麼使用AutoFac? 之前介紹了Unity和Ninject兩個IOC容器,但是發現園子里用AutoFac的貌似更為普遍,於是捯飭了兩天,發現這個東東確實是個高大上的IOC容器~ Autofac是.NET領域最為流行的IOC框架之一,傳說是速度最快的 ...
  • 1.看到標題首先要想到三層架構是什麼? 三層架構其實為: ①表示層:負責接收用戶的輸入,將輸出呈現給用戶, 以及訪問安全性驗證,並對輸入的數據的正確性、 有效性及呈現樣式負責,但對輸出的數據的正確性 不負責。 ②業務邏輯性:負責系統領域業務的處理,負責邏輯性數據的生產、 處理及轉換。對所輸入的邏輯性 ...
  • (一)概述 數組的大小是固定的。如果元素個數是動態的,就應使用集合類。 List<T>是與數組相當的集合類。還有其它類型的集合:隊列、棧、鏈表、字典和集。 (二)列表 1、創建列表 調用預設的構造函數,就可以創建列表對象。在泛型類List<T>中,必須為聲明為列表的值指定類型。使用預設構造函數創建一 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...