c#中抽象類(abstract)和介面(interface)的相同點與區別

来源:http://www.cnblogs.com/reggieqiao/archive/2016/09/19/5886758.html
-Advertisement-
Play Games

相同點: 1、都可以被繼承 2、都不能被實例化 3、都可以包含方法聲明 4、派生類必須實現未實現的方法 區別: 1、抽象基類可以定義欄位、屬性、方法實現。介面只能定義屬性、索引器、事件、和方法聲明,不能包含欄位。 2、抽象類是一個不完整的類,需要進一步細化,而介面是一個行為規範。微軟的自定義介面總是 ...


相同點:

  • 1、都可以被繼承
  • 2、都不能被實例化
  • 3、都可以包含方法聲明
  • 4、派生類必須實現未實現的方法

 

區別:

  • 1、抽象基類可以定義欄位、屬性、方法實現。介面只能定義屬性、索引器、事件、和方法聲明,不能包含欄位。
  • 2、抽象類是一個不完整的類,需要進一步細化,而介面是一個行為規範。微軟的自定義介面總是後帶able欄位,證明其是表述一類“我能做。。。”
  • 3、介面可以被多重實現,抽象類只能被單一繼承
  • 4、抽象類更多的是定義在一系列緊密相關的類間,而介面大多數是關係疏鬆但都實現某一功能的類中
  • 5、抽象類是從一系列相關對象中抽象出來的概念,因此反映的是事物的內部共性;介面是為了滿足外部調用而定義的一個功能約定, 因此反映的是事物的外部特性
  • 6、介面基本上不具備繼承的任何具體特點,它僅僅承諾了能夠調用的方法
  • 7、介面可以用於支持回調,而繼承並不具備這個特點
  • 8、抽象類實現的具體方法預設為虛的,但實現介面的類中的介面方法卻預設為非虛的,當然您也可以聲明為虛的
  • 9、如果抽象類實現介面,則可以把介面中方法映射到抽象類中作為抽象方法而不必實現,而在抽象類的子類中實現介面中方法

 

使用規則:

  • 1、抽象類主要用於關係密切的對象,而介面最適合為不相關的類提供通用功能
  • 2、如果要設計大的功能單元,則使用抽象類;如果要設計小而簡練的功能塊,則使用介面。
  • 3、如果預計要創建組件的多個版本,則創建抽象類。介面一旦創建就不能更改。如果需要介面的新版本,必須創建一個全新的介面。
  • 4、如果創建的功能將在大範圍的全異對象間使用,則使用介面;如果要在組件的所有實現間提供通用的已實現功能,則使用抽象類。
  • 5、分析對象,提煉內部共性形成抽象類,用以表示對象本質,即“是什麼”。為外部提供調用或功能需要擴充時優先使用介面
  • 6、好的介面定義應該是具有專一功能性的,而不是多功能的,否則造成介面污染。如果一個類只是實現了這個介面的中一個功能,而不得不去實現介面中的其他方法,就叫介面污染
  • 7、儘量避免使用繼承來實現組建功能,而是使用黑箱復用,即對象組合。因為繼承的層次增多,造成最直接的後果就是當你調用這個類群中某一類,就必須把他們全部載入到棧中!後果可想而知。(結合堆棧原理理解)。同時,有心的朋友可以留意到微軟在構建一個類時,很多時候用到了對象組合的方法。比如 asp.net中,Page類,有Server Request等屬性,但其實他們都是某個類的對象。使用Page類的這個對象來調用另外的類的方法和屬性,這個是非常基本的一個設計原則

 

例如:

Window窗體可以用抽象類來設計,可以把公有操作和屬性放到一個抽象類里,讓窗體和對話框繼承自這個抽象類,再根據自己的需求進行擴展和完善。

列印操作可以作為一個介面提供給每個需要此功能的窗體,因為窗體的內容不同,就要根據他們自己的要求去實現自己的列印功能。列印時只通過介面來調用,而不用在乎是那個窗體要列印。

 

共性、個性與選擇:

有的書上寫到C#推薦使用介面(Interface)來替代抽象基類(Abstract Class),並強調使用介面的諸多好處,這點我不敢苟同,從上面列表中看來,兩者之間還是存在不少差異的,而這種差異的存在性必然決定了適用場景的不同,例如在抽象基類中可以為部分方法提供預設的實現,從而避免在子類中重覆實現它們,提高代碼的可重用性,這是抽象類的優勢所在;而介面中只能包含抽象方法。至於何時使用抽象基類何時使用介面關鍵還是取決於用戶是如何看待繼承類之間的聯繫的,用戶更加關心的是它們之間的個性差異還是它們之間的共性聯繫。舉個生活中的例子加以說明。

如果給你三個對象分別是人、魚、青蛙,讓你為他們設計個基類來概括它們之間的聯繫,那麼首先給你的感覺肯定是它們個體間的差異性較大,很難抽象出共性,然而若讓你概括他們行為之間的共性,你可能想了想會意識到他們都會游泳,只不過是游泳方式迥異。那麼這時你就應當考慮使用介面而不是抽象基類,原因有三條:

interface ISwim 
{ 
    void Swim(); 
}
 
public class Person : ISwim 
{ 
    public void Swim() 
    { 
        //Swimming in person's style. 
    } 
}
 
public class Frog : ISwim 
{ 
    public void Swim() 
    { 
        //Swimming in frog's style. 
    } 
}
 
public class Fish : ISwim 
{ 
    public void Swim() 
    { 
        //Swimming in fish's style. 
    } 
}
  • 1、個性大於共性。
  • 2、差異較大的個性間具有某些相同的行為。
  • 3、相同行為的實現方式有較大區別。

這時再給你三個對象,分別是鯽魚、鯉魚、金魚,仍然讓你設計基類來概括它們之間的聯繫,那麼你第一個意識到的肯定是它們都屬於魚類,其次是他們游泳的方式可能稍有差異,這時就應當使用抽象基類而不是介面,對比著上面的例子,原因也有三條:

abstract public class Fish 
{ 
    abstract public void Swim(); 
}
 
public class 鯽魚 : Fish 
{ 
    public override void Swim() 
    { 
        //Swim like a 鯽魚 
    } 
}
 
public class 鯉魚 : Fish 
{ 
    public override void Swim() 
    { 
        //Swim like a 鯉魚 
    } 
}
 
public class 金魚 : Fish 
{ 
    public override void Swim() 
    { 
        //Swim like a 金魚 
    } 
}
  • 1、共性大於個性
  • 2、共性相同的個體間必然具有相同的屬性與行為
  • 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 修飾符。

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/fxh_hua/archive/2009/08/20/4464739.aspx


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

-Advertisement-
Play Games
更多相關文章
  • 配置針對應用程式的運行狀況監視的一個服務 配置節內容比以往的較為複雜,如下 實際上這是運行狀況監視是一個事件定義與處理的模型,簡單來看整個運行狀況監視基本點有以下三個 1.在eventMappings定義事件 2.在providers定義事件的處理 3.通過rules綁定事件給某個處理程式去處理。 ...
  • Awesome系列的.Net資源整理。awesome-dotnet是由quozd發起和維護。內容包括:編譯器、壓縮、應用框架、應用模板、加密、資料庫、反編譯、IDE、日誌、風格指南等。 API 框架 NancyFx:輕量、用於構建 HTTP 基礎服務的非正式(low-ceremony)框架,基於.N ...
  • 代碼: 方法一:窗體的代碼-->可以直接通過預設的Click事件來實現控制進度條。 方法二:通過調用其他類里的方法來實現對進度條的控制。 註意一:需要using System.Windows.Forms; 註意二:進度條ToolStripProgressBar的許可權需要改成Public 效果圖:(左 ...
  • 前言 我們知道,在 MVC 應用程式中,有一部分約定的內容。其中關於 Controller 的約定是這樣的。 每個 Controller 類的名字以 Controller 結尾,並且放置在 Controllers 目錄中。 Controller 使用的視圖是在 Views 主目錄的一個子目錄中,這個 ...
  • 接著上期的文章繼續說非同步與並行 並行來自於線程的方法實現,非同步不一定。這句話,暈倒一大片程式員。 首先,多線程式是實現非同步一種方法,兩者的共同目的:使主線程保持對用戶操作的實時響應,如點擊、拖拽、輸入字元等。使主程式看起來實時都保持著等待用戶響應的狀態,而後臺卻有若幹件事情在自己乾。按消耗資源所在地 ...
  • 一、B/S和C/S 1、C/S C/S 架構是一種典型的兩層架構,其全程是Client/Server,即客戶端伺服器端架構,其客戶端包含一個或多個在用戶的電腦上運行的程式,而伺服器端有兩種,一種是資料庫伺服器端,客戶端通過資料庫連接訪問伺服器端的數據;另一種是Socket伺服器端,伺服器端的程式通過 ...
  • using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using Syste ...
  • 想法:將屏幕截圖作為程式背景圖,在之上彈出提示視窗,選擇確定後進行定時圖片隨機位置顯示。(支持ESC鍵退出) 需要添加的控制項:Timer 需要修改的Form1屬性為下圖紅色區域: 資源文件的添加:添加->新建項->資源文件 ESC鍵退出程式: 在Form1.Designer.cs中增加 this.K ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...