1. 程式人生 > >【轉】C#中的兩把雙刃劍:抽象類和接口

【轉】C#中的兩把雙刃劍:抽象類和接口

實例 可維護 對象 為什麽不使用 程序 一定的 代碼 方式 索引

轉:http://www.cnblogs.com/djzxjblogs/p/7587735.html

第一次面試的時候, 面試官問我,抽象類和接口的區別。

本人也是,按照面試寶典上的回答,說了一大堆。

那個面試官又問:你說了一大堆, 有沒有想過他們的本質區別。

當時我真的是沒有想過,但回想平時用的抽象類和接口, 感覺是還是停留在表象,無奈就猜測回答:會不會是抽象類關註的是某類東西, 而接口關註的是行為特征方法等。

其實我當時真的不知道。

問題出現:

我們在使用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)繼承了接口的類必須全部實現接口的方法;

如果想了解官網關於接口的說明,給你一個地址:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/interface

抽象類和接口的區別和聯系:

相同點:(1)都是不能直接實例化,只能通過繼承方式去實現;

(2)都是對事物行為和對象的抽象,形成一定的設計模式;

不同點:

(1)接口支持多繼承;抽象類不能實現多繼承;

(2)接口包括方法、屬性、事件、索引器,不能包括字段;抽象類可以包括字段,也可以包括方法的實現;

(3)接口可以支持回調,抽象類不支持回調

(4)接口可以作為值類型和引用類型基類,而抽象類只能作為引用類型的基類;

第二階段(使用階段):就象問題2一樣,這部分人對基礎有了一定的了解,但就是缺乏一定的實踐,或許就是做個簡單的Demo了事,那麽什麽時候用抽象類,啥時用接口呢?

分析第二個問題,我提出3點建議:

第一個建議,對基礎概念不只是概念的記憶,要多練、多思,然後再多練、再多思,循環幾次,直到熟爛於心;

第二個建議,盡量在自己的項目中使用這方面的知識,去使用它,你才能發現問題,解決問題,才會思考;

第三個建議,對自己使用過的抽象類和接口的項目的知識點進行總結和歸納;
就什麽時候使用抽象類和接口,我總結前輩的經驗,給出以下幾點,僅供參考:

(1)當設計的組件將來有多個版本的時候一般使用抽象類,例如用C#設計數據庫DB,剛開始你可能使用的是sql server ,mysql,以後大型的項目可能要使用oracle,DB這種大型的數據庫系統,那麽我們在設計類的時候就設計一個抽象的基類DB,讓它具有 數據的一些通用的屬性和方法,屬性:數據庫的連接名,版本,數據庫類型,數據庫的通用方法:Open(),Close()方法等;

(2)當設計的組件同時支持通用的行為動作,可以考慮接口;例如鳥類,人類,車類都可以有聲音,這時候可以設計接口,包含叫的函數行為,然後在各個具體的類中實現;

(3)在繼承了接口的派生類或接口中,一旦該接口需要增加行為方法是個比較頭疼的事情,必須所有的繼承都必須實現它的方法,這個時候可以在派生類去實現一個新增的接口,來實現派生類的獨特動作,


以上代碼,只是說明問題,比較簡單;
第三階段(優化階段):就象問題3一樣,我們在做一個抽象類或者接口的時候首先考慮的是能用就行,結果就是定義的類或接口比較多,難以維護和擴展,或者就是類之間有交集,那怎麽優化繼承關系?怎樣才能使得程序具有可維護性和擴展性呢?
我個人建議具備以下幾個方面方可:
(1)要有紮實的基礎知識和深厚的基礎功底;
(2)要有一個多問、多思的心;對於抽象類和接口多問問,為什麽不使用抽象類而要使用接口?為什麽在這個地方使用接口合適?
(3)多看看前輩們是怎麽設計接口和類的,這方面的資料網上搜搜不少;
(4)個人建議多看看設計模式這方面的知識,因為他們是前輩在設計時的經驗和思想;

【轉】C#中的兩把雙刃劍:抽象類和接口