抽象类 VS 接口
引言
接口和抽象類是面向對象編程(OOP, Object Oriented programming)中兩個繞不開的概念,二者相似而又有所不同。接下來,我們來了解二者的概念并比較它們的異同。
什么是抽象類型?
抽象類是一種特殊的類,該類不能被實例化。抽象類的存在就是為了被繼承,即抽象類可以被其它類繼承但不能被實例化。那么,我們為什么需要一個無法被實例化的類呢?這樣做的優點是,通過抽象類我們制定了一份強制所有子類必須遵守的合約,使所有子類有著一致的層次結構。抽象類提供了一種規范用于規定子類如何進行工作,子類可根據自身情況來重寫抽象類中的抽象成員(及其它可被重寫的成員)以滿足自身需求。
抽象類作為一個基類,可以包含已實現的成員,同時應至少包含一個抽象成員,否則就沒必要使用抽象類了。如果一個抽象類中僅僅包含抽象方法,那么這時抽象類就和接口很像了。
什么是接口?
接口中不能包含任何被實現的成員,即接口中只能包含成員的簽名。如,沒有方法體的方法、只包含訪問器關鍵字(set、get)的屬性等。和抽象類類似,接口也是一份合約。C#中,接口和抽象類的主要區別是,類可以實現多個接口,但只能繼承一個(抽象)類。
比較異同
| 是否支持多繼承 | 支持 | 不支持 |
| 默認實現 | 接口中不能包含任何已實現的成員 | 抽象類中可以包含已實現(非抽象)的成員 |
| 訪問修飾符 | 接口成員默認是公共(public)的,不再允許被任何訪問修飾符修飾 | 抽象類成員可以被訪問修飾符(不能是private)修飾 |
| 核心 VS 輔助 | 接口多用于定義(輔助性的)能力 | 抽象類多用于定義相同類型(這里類型不是數據類型的意思,解釋見下文)子類所共有的一些特征 |
| ? | 若只提供一些方法上的約束,建議使用接口 | 如果子類屬于同一類型,且具有相同的行為或狀態,建議使用抽象類提供約束 |
| 尋找成員速度 | 相比抽象類較慢 | 相比接口更快 |
| 成員變動的影響 | 如果接口成員發生改動,則所有實現類都要進行改動 | 若向抽象類中添加非抽象成員,我們可以給該成員提供默認實現,這樣子類就無需發生變動 |
| 允許包含的抽象成員 | 屬性、方法、事件、索引器(這四類本質上都是方法) | 屬性、方法、事件、索引器 |
| 是否允許定義字段 | 不允許 | 不允許定義使用abstract修飾的字段 |
抽象類是對子類的抽象,即將子類中的公共部分提取出來,放到一個特定的類中。抽象類是一份合約,用于為同一類型(這里類型不是指數據類型,而是邏輯上的劃分,如人和貓都是動物)的子類提供約束。
接口也是一份合約,但接口多用對能力的定義,即用于指定實現類能做哪些事兒。
人和貓,都屬于動物這個大類,我們可以抽象出二者的公共部分。如,年齡、體重、吃、會叫(用于形容人不太友好)等作為一個抽象類的成員。
abstract class Animal {public abstract int Age { set; get; }public abstract float Weight { set; get; }public abstract void Call();//默認實現public virtual void Eat(){Console.WriteLine("貓糧......");} }class Person : Animal {public override int Age { set; get; }public override float Weight { set; get; }public override void Eat(){Console.WriteLine("魚香肉絲蓋飯......");}public override void Call(){Console.WriteLine("雷好啊......");} }class Cat : Animal {public override int Age { set; get; }public override float Weight { set; get; }public override void Call(){Console.WriteLine("喵喵喵......");} }?
那么,只要繼承Animal類的類都應屬于動物這個大類,汽車就不應該繼承Animal類。
此外,人和貓相比,人會制作工具而貓不行,那么制作工具的技能就是人所特有的,這時可以定義一個接口提供對制作工具這項技能的約束,然后讓Person類實現該接口。
?
再如,人、車、貓三者都可以跑,那么也可以定義個接口用于對跑這項技能提供約束。
interface IRun {void Run(); }class Person : IRun {public void Run(){Console.WriteLine("11路公交......");} }class Cat : IRun {public void Run(){Console.WriteLine("四蹄奔騰......");} }class Car : IRun {public void Run(){Console.WriteLine("四輪......");} }?
小結
用簡單的話概括接口和抽象類的異同:
-
抽象類和接口都是一種約束,這種約束使我們的代碼有更好的層次結構,特別是在多人協同開發時(若每個人都按照自己的習慣來,對整個開發團隊而言,開發成本不知要提高多少)。
-
抽象類是對相同類型(不是數據類型)子類公共部分的抽象(約束),接口是對能力的一種約束。
此外,建議大家讀一讀文末給出的這篇文章,本人讀完收益頗多,本文中的表格部分引自該文。
參考文章
Abstract Class versus Interface
版權聲明
本文為作者原創,版權歸作者雪飛鴻所有。 轉載必須保留文章的完整性,且在頁面明顯位置處標明原文鏈接。
如有問題, 請發送郵件和作者聯系。
轉載于:https://www.cnblogs.com/Cwj-XFH/p/6225292.html
總結
- 上一篇: Python之路【第一篇】:Python
- 下一篇: Javascript数组操作(转)