走進C# abstract,了解抽象類與接口的異同
前言:
最近在研究.NET Core的一些類庫源碼的時候發現在底層類庫中使用了大量的抽象類,然而發現自己搬磚這麼多年好像從來沒有在項目中使用抽象類或者抽象方法去實現某個功能模塊,並且對修飾符Abstract概念也只懂得一些皮毛(也就是面試的時候會問下其基本作用)。當然,咱們不懂就要去慢慢的學習了解,不能讓這些不懂的技術和知識點一直困擾着我們。接下來就讓我們一起去探索C# Abstract修飾符的作用,並且了解在什麼場景下我們會使用到抽象類,從而提升我們項目的健壯性。
abstract修飾符:
基本概念:abstract修飾符指示要修改的東西有缺失或不完整的實現。
修飾範圍:abstract修飾符可以用於修飾類、方法、屬性、索引器(indexer)和事件。
抽象類:
public abstract class HttpRequest{}
抽象方法:
//todo:抽象方法不能提供實際的實現,因此沒有方法主體(並且抽象方法只能夠在抽象類中聲明) public abstract void ActionMethod();
抽象屬性:
public abstract string ContentType { get; set; }
抽象索引器:
public string this[int index] => $"獲取_{index}";
抽象事件:
//首先聲明該事件的委託類型 public delegate void BoilerLogHandler(string status); // 基於上面的委託定義事件 public abstract event BoilerLogHandler BoilerEventLog;
抽象類與接口的異同:
抽象類的用途:
是一個能夠提供給多個派生類共享的通用基類。
接口的用途:
接口提供了派生類應遵循的標準結構。
抽象類的基本特徵:
1、抽象類是特殊的類,除了不能實例化(只能通過實例化繼承抽象方法的派生類來獲取抽象類中的成員)外,具有類的其他特性(可以單繼承)。
2、抽象類可以定義抽象方法,抽象方法沒有現實。
3、繼承抽象類的類必須把裏面的抽象成員(成員包括:方法,屬性,索引器,事件)全部重寫(orveride),抽象類除外。
接口的基本特徵:
1、接口無法直接進行實例化。
2、一個類或結構可以實現多個接口。
3、實現接口的任何類或結構都必須實現其所有成員。
4、接口包含的成員只有方法,屬性,索引器(有參屬性),事件四種成員。
5、接口不能包含實例字段、實例構造函數或終結器。
6、默認情況下,接口成員是公共的,不能有其他的修飾符。
抽象類和接口的區別:
相同:
1、都可以被繼承
2、都不能直接被實例化
3、都可以包含方法聲明且都沒有實現
4、派生類必須實現未實現的成員
不同點:
1、接口可以被多重實現,抽象類只能被單一繼承。
2、接口可以用於支持回調,繼承並不具備這個特點。
3、抽象類可以定義字段、方法、屬性、事件、索引器的實現。接口只能定義屬性、索引器、事件、和方法聲明,不能包含字段。
4、接口中的成員訪問類型默認為公共的,不能有其他的訪問修飾符修飾。
5、定義的關鍵字不一樣,抽象類需要使用abstract,而接口則使用interface。
抽象類和接口的使用:
1、抽象類表共性(常應用在具有相同的行為和特徵中),而接口則表規範(用於定義一種行為)。
2、抽象類主要用於關係密切的對象,而接口最適合為不相關的類提供通用功能。
3、如果要設計大的功能單元,則使用抽象類;如果要設計小而簡練的功能塊,則使用接口。
4、如果預計要創建組件的多個版本,則創建抽象類。接口一旦創建就不能更改。如果需要接口的新版本,必須創建一個全新的接口。
5、如果創建的功能將在大範圍的全異對象間使用,則使用接口;如果要在組件的所有實現間提供通用的已實現功能,則使用抽象類。
6、分析對象,提煉內部共性形成抽象類,用以表示對象本質,即「是什麼」。為外部提供調用或功能需要擴充時優先使用接口。
7、好的接口定義應該是具有專一功能性的,而不是多功能的,否則造成接口污染。如果一個類只是實現了這個接口的中一個功能,而不得不去實現接口中的其他方法,就叫接口污染。
具體實例如下:
實例一:就像鐵門木門都是門(抽象類),你想要個門我給不了(不能實例化),但我可以給你個具體的鐵門或木門(多態);而且只能是門,你不能說它是窗(單繼承);一個門可以有鎖(接口)也可以有門鈴(多實現)。 門(抽象類)定義了你是什麼,接口(鎖)規定了你能做什麼(一個接口最好只能做一件事,你不能要求鎖也能發出聲音吧(接口污染))。
實例二:比如說我們一個班級有很多為同學,這些同學都有着各自的特長,愛好,穿衣打扮的風格,因此我們減少代碼冗餘可以定義一個通用的學生抽象類用來描述學生的身高,體重,姓名,愛好,特徵等相關特徵和行為的公共抽象類。
實例三:我們需要創建 「狗」、「貓」、「魚」、「馬」這些對象(類),我們可以說他們有一些共同的屬性像嘴巴、尾巴、重量、顏色、大小等等一些共同的屬性(properties),但是它們彼此的屬性的形狀是不同的(如嘴巴),在這種情況下,我們如果一個個去定義各自類似的屬性是不是比較繁瑣?如果用抽象類是不是很方便的給他們去繼承。抽象類也有個更加好的地方,體現在「同質異像」就是實質相同實現形式不同的方法繼承上,例如上面的狗、貓、馬等的呼吸這個方法或者跑的速度的方法形式不同,我們這個是用定義一個抽象方法,讓他們各自的類去實現它是不是很方便。「抽象」的意義正在於此。將共同的東西抽出來封裝,但不實現只給繼承。
總結:
通過對抽象類的深入理解發現原來在程序設計方面需要考慮優化的問題還是有很多很多的,抽象類和接口的選擇就是一個很典型的例子。往往我們會圖簡單而去直接定義接口使用,卻往往忽視了後期的軟件的健壯性和可拓展性。在以後的開發中需要多思考這方面的問題。最後假如文章有什麼需要補充或者不足的地方希望大家指正,謝謝。
參考資料:
//docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/abstract-and-sealed-classes-and-class-members
//blog.csdn.net/lizhenxiqnmlgb/article/details/82346478
//kb.cnblogs.com/page/41836/