問題出現:
我們在使用C#的抽象類別和介面的時候,往往會遇到以下類似的問題,大致歸納如下:
( 1)抽象類別和介面有什麼本質的差別和連結?
(2)什麼時候選擇使用抽象類,但時候使用介面最恰當呢?
(3)在專案中怎麼使用才能讓專案更有可維護性、擴充性?怎樣將它和Struct,類緊密的結合,達到最終的雙面刃作用?
解決方案:
這也是我在學習抽象類別和介面的時候遇到的問題,從我歸納的這三個問題,不難看出這也許是我們大多數程式設計師遇到問題的三個階段,
#第一階段(基礎概念):就像問題1一樣,這部分人首先需要掃清基礎概念的障礙,首先得懂得什麼叫抽象類,什麼叫接口?
然後了解抽象類別和介面之間的差異和聯繫是什麼?當然這可能需要一段時間去理解和實踐,畢竟這些概念比較抽象,屬於那種摸不著看不到的東西,當然最主要還是多練習,沒事的時候做個Demo實例,把它們都使用一遍,在使用的過程中多想想為什麼要這樣用?這用有什麼好處?能不能使用介面呢,如果不能,使用抽象類別好處又在哪?這樣可以加深對它們的理解,這也是我的一點經驗吧,呵呵!說了這麼多,我還是把問題1總結一下,一是方便自己記,二是加深理解吧。
抽象類別和介面的概念:其實這些概念在教科書和部落格基本上一大堆,前輩們總結的也很好了,但是可能在通俗、易懂方面有點晦澀難懂,我就翻譯一下,加點陝西版的白話文,嘿嘿。
(1)抽象類別:提供了一組衍生類別存取共享基底類別的公共方法;
抽象類別的特性是:(1)抽象類別既包括抽象方法,也可以包括方法的實作;(2)抽象類別不能被實例化,也不能被密封;(3)抽象類別中的抽象方法要麼在衍生類別中實現,要麼用派生抽象類別繼承(抽象衍生類別可以繼承基底類別抽象方法的),如果要在衍生類別中實作基底類別的抽象方法,必須使用override 修飾符;(4)抽象類別屬於單一繼承(這點屬於所有類別的同性,在這提一下)(5)抽象類別是一族群的抽象,類似IS-A;
以上我如果說的還不是很清楚,給你個官網的關於抽象類別的位址:https://docs.microsoft.com/ en-us/dotnet/csharp/language-reference/keywords/abstract
(2)介面:包含了一組虛擬方法的抽象類型;
介面的特性是:(1)介面中只包括虛擬方法的定義,只有聲明定義,沒有函數實作;(2)介面類別中可以包括屬性、事件、索引器等,但不能包含欄位;(3)介面類別屬於多重繼承;(4)繼承了介面的類別必須全部實作介面的方法;
抽象類別和介面的區別和聯繫:
相同點:(1)都是不能直接實例化,只能透過繼承方式去實現;
(2)都是對事物行為和物件的抽象,形成一定的設計模式;
不同點:
(1)介面支援多重繼承;抽象類別不能實現多重繼承;
(2)介麵包括方法、屬性、事件、索引器,不能包括欄位;抽象類別可以包括字段,也可以包括方法的實作;
(3)介面可以支援回調,抽象類別不支援回呼
(4)介面可以作為值類型和引用型別基類,而抽象類別只能作為引用型別的基底類;
第二階段(使用階段):就像問題2一樣,這部分人對基礎有了一定的了解,但就是缺乏一定的實踐,或許就是做個簡單的Demo了事,那麼什麼時候用抽象類,啥時用介面呢?
分析第二個問題,我提出3點建議:
第一個建議,對基礎概念不只是概念的記憶,要多練、多思,然後再多練、再多思,循環幾次,直到熟爛於心;
第二個建議,盡量在自己的專案中使用這方面的知識,去使用它,你才能發現問題,解決問題,才會思考;
第三個建議,對自己使用過的抽象類別和接口的項目的知識點進行總結和歸納;
就什麼時候使用抽象類別和接口,我總結前輩的經驗,給以下幾點,僅供參考:
(1)當設計的元件將來有多個版本的時候一般使用抽象類,例如用C#設計資料庫DB,剛開始你可能使用的是sql server ,mysql,以後大型的專案可能要使用oracle, DB這個大型的資料庫系統,那麼我們在設計類別的時候就設計一個抽象的基底類別DB,讓它有 資料的一些通用的屬性和方法,屬性:資料庫的連接名,版本,資料庫類型,資料庫的通用方法:Open(),Close()方法等;
(2)當設計的組件同時支援通用的行為動作,可以考慮介面;例如鳥類,人類,車類都可以有聲音,這時候可以設計接口,包含叫的函數行為,然後在各個具體的類別中實現;
(3)在繼承了接口的派生類或接口中,一旦該接口需要增加行為方法是個比較頭痛的事情,必須所有的繼承都必須實現它的方法,這個時候可以在派生類去實現一個新增的接口,來實現派生類的獨特動作,舉例說明:
/// <summary> /// 实现一个爬行动物的动作接口 /// </summary> interface IAnimalClimb { void Climb(); } /// <summary> /// 实现一个会叫的动物的动作接口 /// </summary> interface ICry { void Cry(); } /// <summary> /// 实现一个动物抽象类 /// </summary> public abstract class Animal { //动物的名字 public string Name { get; set; } //动物的颜色 public string Color { get; set; } //动物抽象类的共有方法 public abstract void Sleep(); public abstract void Breathe(); } /// <summary> /// 定义鸟类,通用方法是会飞 /// </summary> public class Bird : Animal,ICry { public override void Sleep() { Console.WriteLine("Bird派生类继承了基类的Sleep()方法"); } public override void Breathe() { Console.WriteLine("Bird派生类继承了基类的Breathe()方法"); } //鸟类可以继承统一的接口动作,例如:叫 public void Cry() { Console.WriteLine("Bird派生类继承了接口ICry的叫的方法"); } } /// <summary> /// 定义爬行动物类 /// </summary> public class Snake : Animal, IAnimalClimb { public override void Breathe() { Console.WriteLine("Snake派生类继承了基类的Sleep()方法"); } public override void Sleep() { Console.WriteLine("Snake派生类继承了基类的Sleep()方法"); } //爬行动物可以继承统一的接口动物,例如:爬 public void Climb() { Console.WriteLine("Snake派生类继承了接口IAnimalClimb的爬的方法"); } }
以上程式碼,只是說明問題,比較簡單;
第三階段(優化階段):就像問題3一樣,我們在做一個抽象類別或介面的時候首先考慮的是能用就行,結果就是定義的類或介面比較多,難以維護和擴展,或是類別之間有交集,那怎麼優化繼承關係?怎麼樣才能使得程式具有可維護性和擴充性?
我個人建議具備以下幾個面向方可:
(1)要有紮實的基礎知識和深厚的基礎功底;
(2)要有一個多問、多思的心;對於抽象類別和介面多問,為什麼不使用抽象類別而要使用介面?為什麼在這個地方使用介面合適?
(3)多看看前輩們是怎麼設計介面和類別的,這方面的資料網上搜搜不少;
(4)個人建議多看看設計模式這方面的知識,因為他們是前輩設計時的經驗與想法;
以上是C#中的抽象類別與介面的詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!