- 一、均可以被繼承
- 二、都不能被實例化
- 三、均可以包含方法聲明
- 四、派生類必須實現未實現的方法
區別:
- 一、抽象基類能夠定義字段、屬性、方法實現。接口只能定義屬性、索引器、事件、和方法聲明,不能包含字段。
- 二、抽象類是一個不完整的類,須要進一步細化,而接口是一個行爲規範。微軟的自定義接口老是後帶able字段,證實其是表述一類「我能作。。。」
- 三、接口能夠被多重實現,抽象類只能被單一繼承
- 四、抽象類更多的是定義在一系列緊密相關的類間,而接口大多數是關係疏鬆但都實現某一功能的類中
- 五、抽象類是從一系列相關對象中抽象出來的概念,所以反映的是事物的內部共性;接口是爲了知足外部調用而定義的一個功能約定, 所以反映的是事物的外部特性
- 六、接口基本上不具有繼承的任何具體特色,它僅僅承諾了可以調用的方法
- 七、接口能夠用於支持回調,而繼承並不具有這個特色
- 八、抽象類實現的具體方法默認爲虛的,但實現接口的類中的接口方法卻默認爲非虛的,固然您也能夠聲明爲虛的
- 九、若是抽象類實現接口,則能夠把接口中方法映射到抽象類中做爲抽象方法而沒必要實現,而在抽象類的子類中實現接口中方法
使用規則:
- 一、抽象類主要用於關係密切的對象,而接口最適合爲不相關的類提供通用功能
- 二、若是要設計大的功能單元,則使用抽象類;若是要設計小而簡練的功能塊,則使用接口。
- 三、若是預計要建立組件的多個版本,則建立抽象類。接口一旦建立就不能更改。若是須要接口的新版本,必須建立一個全新的接口。
- 四、若是建立的功能將在大範圍的全異對象間使用,則使用接口;若是要在組件的全部實現間提供通用的已實現功能,則使用抽象類。
- 五、分析對象,提煉內部共性造成抽象類,用以表示對象本質,即「是什麼」。爲外部提供調用或功能須要擴充時優先使用接口
- 六、好的接口定義應該是具備專注功能性的,而不是多功能的,不然形成接口污染。若是一個類只是實現了這個接口的中一個功能,而不得不去實現接口中的其餘方法,就叫接口污染
- 七、儘可能避免使用繼承來實現組建功能,而是使用黑箱複用,即對象組合。由於繼承的層次增多,形成最直接的後果就是當你調用這個類羣中某一類,就必須把他們所有加載到棧中!後果可想而知。(結合堆棧原理理解)。同時,有心的朋友能夠留意到微軟在構建一個類時,不少時候用到了對象組合的方法。好比 asp.net中,Page類,有Server Request等屬性,但其實他們都是某個類的對象。使用Page類的這個對象來調用另外的類的方法和屬性,這個是很是基本的一個設計原則
例如:
Window窗體能夠用抽象類來設計,能夠把公有操做和屬性放到一個抽象類裏,讓窗體和對話框繼承自這個抽象類,再根據本身的需求進行擴展和完善。編程
打印操做能夠做爲一個接口提供給每一個須要此功能的窗體,由於窗體的內容不一樣,就要根據他們本身的要求去實現本身的打印功能。打印時只經過接口來調用,而不用在意是那個窗體要打印。設計模式
共性、個性與選擇:
有的書上寫到C#推薦使用接口(Interface)來替代抽象基類(Abstract Class),並強調使用接口的諸多好處,這點我不敢苟同,從上面列表中看來,二者之間仍是存在很多差別的,而這種差別的存在性必然決定了適用場景的不一樣,例如在抽象基類中能夠爲部分方法提供默認的實現,從而避免在子類中重複實現它們,提升代碼的可重用性,這是抽象類的優點所在;而接口中只能包含抽象方法。至於什麼時候使用抽象基類什麼時候使用接口關鍵仍是取決於用戶是如何看待繼承類之間的聯繫的,用戶更加關心的是它們之間的個性差別仍是它們之間的共性聯繫。舉個生活中的例子加以說明。asp.net
若是給你三個對象分別是人、魚、青蛙,讓你爲他們設計個基類來歸納它們之間的聯繫,那麼首先給你的感受確定是它們個體間的差別性較大,很難抽象出共性,然而若讓你歸納他們行爲之間的共性,你可能想了想會意識到他們都會游泳,只不過是游泳方式迥異。那麼這時你就應當考慮使用接口而不是抽象基類,緣由有三條:ide
1 interface ISwim
2 {
3 void Swim();
4 }
5
6 public class Person : ISwim
7 {
8 public void Swim()
9 {
10 //Swimming in person's style.
11 }
12 }
13
14 public class Frog : ISwim
15 {
16 public void Swim()
17 {
18 //Swimming in frog's style.
19 }
20 }
21
22 public class Fish : ISwim
23 {
24 public void Swim()
25 {
26 //Swimming in fish's style.
27 }
28 }
- 一、個性大於共性。
- 二、差別較大的個性間具備某些相同的行爲。
- 三、相同行爲的實現方式有較大區別。
這時再給你三個對象,分別是鯽魚、鯉魚、金魚,仍然讓你設計基類來歸納它們之間的聯繫,那麼你第一個意識到的確定是它們都屬於魚類,其次是他們游泳的方式可能稍有差別,這時就應當使用抽象基類而不是接口,對比着上面的例子,緣由也有三條:post
1 abstract public class Fish
2 {
3 abstract public void Swim();
4 }
5
6 public class 鯽魚 : Fish
7 {
8 public override void Swim()
9 {
10 //Swim like a 鯽魚
11 }
12 }
13
14 public class 鯉魚 : Fish
15 {
16 public override void Swim()
17 {
18 //Swim like a 鯉魚
19 }
20 }
21
22 public class 金魚 : Fish
23 {
24 public override void Swim()
25 {
26 //Swim like a 金魚
27 }
28 }
- 一、共性大於個性
- 二、共性相同的個體間必然具備相同的屬性與行爲
- 三、相同行爲的實現方式具備必定區別
觀察在使用接口或是使用抽象基類的幾條理由中,第三條理由實際上是同樣的,它所描述的是面向對象中多態的概念,即經過覆蓋父類的方法來實現,在運行時根據傳遞的對象引用,來調用相應的方法。第二條理由開始產生分歧,接口更增強調了繼承對象間具備相同的行爲,而抽象類同時還強調了繼承對象間具備相同的屬性。而真正將接口與抽象基類區分開的則是理由概括以下:學習
- 當在差別較大的對象間尋求功能上的共性時,使用接口。
- 當在共性較多的對象間尋求功能上的差別時,使用抽象基類。
經過相同與不一樣的比較,咱們只能說接口和抽象類,各有所長,但無優略。在實際的編程實踐中,咱們要視具體狀況來酌情量才,可是如下的經驗和積累,或許能給你們一些啓示,除了個人一些積累以外,不少都來源於經典,我相信經得起考驗。因此在規則與場合中,咱們學習這些經典,最重要的是學以至用,固然我將以一家之言博你們之笑,看官請繼續。spa
規則與場合:
- 一、請記住,面向對象思想的一個最重要的原則就是:面向接口編程。
- 二、藉助接口和抽象類,23個設計模式中的不少思想被巧妙的實現了,我認爲其精髓簡單說來就是:面向抽象編程。
- 三、抽象類應主要用於關係密切的對象,而接口最適合爲不相關的類提供通用功能。
- 四、接口着重於CAN-DO關係類型,而抽象類則偏重於IS-A式的關係;
- 五、接口多定義對象的行爲;抽象類多定義對象的屬性;
- 六、接口定義可使用public、protected、internal 和private修飾符,可是幾乎全部的接口都定義爲public,緣由就沒必要多說了。
- 七、「接口不變」,是應該考慮的重要因素。因此,在由接口增長擴展時,應該增長新的接口,而不能更改現有接口。
- 八、儘可能將接口設計成功能單一的功能塊,以.NET Framework爲例,IDisposable、IDisposable、IComparable、IEquatable、IEnumerable等都只包含一個公共方法。
- 九、接口名稱前面的大寫字母「I」是一個約定,正如字段名如下劃線開頭同樣,請堅持這些原則。
- 十、在接口中,全部的方法都默認爲public。
- 十一、若是預計會出現版本問題,能夠建立「抽象類」。例如,建立了狗(Dog)、雞(Chicken)和鴨(Duck),那麼應該考慮抽象出動物(Animal)來應對之後可能出現風馬牛的事情。而向接口中添加新成員則會強制要求修改全部派生類,並從新編譯,因此版本式的問題最好以抽象類來實現。
- 十二、從抽象類派生的非抽象類必須包括繼承的全部抽象方法和抽象訪問器的實實現。
- 1三、對抽象類不能使用new關鍵字,也不能被密封,緣由是抽象類不能被實例化。
- 1四、在抽象方法聲明中不能使用 static 或 virtual 修飾符。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/fxh_hua/archive/2009/08/20/4464739.aspx.net