[你必须知道的.NET] 第二回:对抽象编程:接口和抽象类
?本文將介紹以下內容:
? 面向對象思想:多態
? 接口
? 抽象類
?1.?引言
在我之前的一篇post《抽象類和接口的誰是誰非》中,和同事管偉的討論,得到很多朋友的關注,因為是不成體系的論道,所以給大家了解造成不便,同時關于這個主題的系統性理論,我認為也有必要做以總結,因此才有了本篇的新鮮出爐。同時,我將把上貼中的問題順便也在此做以交代。
2. 概念引入
- 什么是接口?
接口是包含一組虛方法的抽象類型,其中每一種方法都有其名稱、參數和返回值。接口方法不能包含任何實現,CLR允許接口可以包含事件、屬性、索引器、靜態方法、靜態字段、靜態構造函數以及常數。但是注意:C#中不能包含任何靜態成員。一個類可以實現多個接口,當一個類繼承某個接口時,它不僅要實現該接口定義的所有方法,還要實現該接口從其他接口中繼承的所有方法。
定義方法為:
????public?interface?System.IComparable
????{
????????int?CompareTo(object?o);
????}
????public?class?TestCls:?IComparable
????{
????????public?TestCls()
????????{
????????}?
????????private?int?_value;
????????public?int?Value
????????{
????????????get?{?return?_value;?}
????????????set?{?_value?=?value;?}
????????}?
????????public?int?CompareTo(object?o)
????????{
????????????//使用as模式進行轉型判斷
????????????TestCls?aCls?=?o?as?TestCls;
????????????if?(aCls?!=?null)
????????????{
????????????//實現抽象方法
????????????return?_value.CompareTo(aCls._value);
????????????}
????????}
????}
?
- 什么是抽象類?
抽象類提供多個派生類共享基類的公共定義,它既可以提供抽象方法,也可以提供非抽象方法。抽象類不能實例化,必須通過繼承由派生類實現其抽象方法,因此對抽象類不能使用new關鍵字,也不能被密封。如果派生類沒有實現所有的抽象方法,則該派生類也必須聲明為抽象類。另外,實現抽象方法由overriding方法來實現。
定義方法為:
///?<summary>
///?定義抽象類
///?</summary>
abstract?public?class?Animal
{
????//定義靜態字段
????protected?int?_id;?
????//定義屬性
????public?abstract?int?Id
????{
????????get;
????????set;
????}?
????//定義方法
????public?abstract?void?Eat();?
????//定義索引器
????public?string?this[int?i]
????{
????????get;
????????set;
????}?
}?
///?<summary>
///?實現抽象類
///?</summary>
public?class?Dog:?Animal
{
????public?override?int?Id
????{
????????get?{return?_id;}
????????set?{_id?=?value;}
????}?
????public?override?void?Eat()
????{
????????Console.Write("Dog?Eats.")
????}
}?
3. 相同點和不同點
3.1 相同點
- 都不能被直接實例化,都可以通過繼承實現其抽象方法。
- 都是面向抽象編程的技術基礎,實現了諸多的設計模式。
3.2 不同點
- 接口支持多繼承;抽象類不能實現多繼承。
- 接口只能定義抽象規則;抽象類既可以定義規則,還可能提供已實現的成員。
- 接口是一組行為規范;抽象類是一個不完全的類,著重族的概念。
- 接口可以用于支持回調;抽象類不能實現回調,因為繼承不支持。
- 接口只包含方法、屬性、索引器、事件的簽名,但不能定義字段和包含實現的方法;抽象類可以定義字段、屬性、包含有實現的方法。?
- 接口可以作用于值類型和引用類型;抽象類只能作用于引用類型。例如,Struct就可以繼承接口,而不能繼承類。
?通過相同與不同的比較,我們只能說接口和抽象類,各有所長,但無優略。在實際的編程實踐中,我們要視具體情況來酌情量才,但是以下的經驗和積累,或許能給大家一些啟示,除了我的一些積累之外,很多都來源于經典,我相信經得起考驗。所以在規則與場合中,我們學習這些經典,最重要的是學以致用,當然我將以一家之言博大家之笑,看官請繼續。
3.3 規則與場合
以上的規則,我就厚顏無恥的暫定為T14條吧,寫的這么累,就當一時的獎賞吧。大家也可以互通有無,我將及時修訂。
4. 經典示例
4.1 絕對經典
.NET Framework是學習的最好資源,有意識的研究FCL是每個.NET程序員的必修課,關于接口和抽象類在FCL中的使用,我有以下的建議:
4.2?別樣小菜
下面的實例,因為是我的理解,因此給經典打上“相對”的記號,至于什么時候晉升為“絕對”,就看我在.NET追求的路上,是否能夠一如既往的如此執著,因此我將把相對重構到絕對為止(呵呵)。 本示例沒有闡述抽象類和接口在設計模式中的應用,因為那將是另一篇有討論價值的文本,本文著眼與概念和原則的把握,但是真正的應用來自于具體的需求規范。
設計結構如圖所示:
?
1.?定義抽象類
????public?abstract?class?Animal????{
????????protected?string?_name;
????????//聲明抽象屬性
????????public?abstract?string?Name
????????{
????????????get;
????????}
????????//聲明抽象方法
????????public?abstract?void?Show();
????????//實現一般方法
????????public?void?MakeVoice()
????????{
????????????Console.WriteLine("All?animals?can?make?voice!");
????????}
????}
2.?定義接口
????{
????????//定義公共方法標簽
????????void?Move();
????}
3. 實現抽象類和接口
????public?class?Duck?:?Animal,?IAction
????{
????????public?Duck(string?name)
????????{
????????????_name?=?name;
????????}
????????//重載抽象方法
????????public?override?void?Show()
????????{
????????????Console.WriteLine(_name?+?"?is?showing?for?you.");
????????}
????????//重載抽象屬性
????????public?override?string?Name
????????{
????????????get?{?return?_name;}
????????}
????????//實現接口方法
????????public?void?Move()
????????{
????????????Console.WriteLine("Duck?also?can?swim.");
????????}
????}
????public?class?Dog?:?Animal,?IAction
????{
????????public?Dog(string?name)
????????{
????????????_name?=?name;
????????}
????????public?override?void?Show()
????????{
????????????Console.WriteLine(_name?+?"?is?showing?for?you.");
????????}
????????public?override?string?Name
????????{
????????????get?{?return?_name;?}
????????}
????????public?void?Move()
????????{
????????????Console.WriteLine(_name?+?"?also?can?run.");
????????}
????}
4.?客戶端實現
????public?class?TestAnmial
????{
????????public?static?void?Main(string?[]?args)
????????{
????????????Animal?duck?=?new?Duck("Duck");
????????????duck.MakeVoice();
????????????duck.Show();
????????????Animal?dog?=?new?Dog("Dog");
????????????dog.MakeVoice();
????????????dog.Show();
????????????IAction?dogAction?=?new?Dog("A?big?dog");
????????????dogAction.Move();
????????}
????}
5. 他山之石
正所謂真理是大家看出來的,所以將園子里有創新性的觀點潛列于此,一是感謝大家的共享,二是完善一家之言的不足,希望能夠將領域形成知識,受用于我,受用于眾。
- dunai認為:抽象類是提取具體類的公因式,而接口是為了將一些不相關的類“雜湊”成一個共同的群體。至于他們在各個語言中的句法,語言細節并不是我關心的重點。
- 樺山澗的收藏也很不錯。
- Artech認為:所代碼共用和可擴展性考慮,盡量使用Abstract Class。當然接口在其他方面的優勢,我認為也不可忽視。
- shenfx認為:當在差異較大的對象間尋求功能上的共性時,使用接口;當在共性較多的對象間尋求功能上的差異時,使用抽象基類。
????????? 最后,MSDN的建議是:
- 如果預計要創建組件的多個版本,則創建抽象類。抽象類提供簡單易行的方法來控制組件版本。通過更新基類,所有繼承類都隨更改自動更新。另一方面,接口一旦創建就不能更改。如果需要接口的新版本,必須創建一個全新的接口。
- 如果創建的功能將在大范圍的全異對象間使用,則使用接口。抽象類應主要用于關系密切的對象,而接口最適合為不相關的類提供通用功能。
- 如果要設計小而簡練的功能塊,則使用接口。如果要設計大的功能單元,則使用抽象類。
- 如果要在組件的所有實現間提供通用的已實現功能,則使用抽象類。抽象類允許部分實現類,而接口不包含任何成員的實現。
6. 結論
接口和抽象類,是論壇上、課堂間討論最多的話題之一,之所以將這個老話題拿出來再議,是因為從我的體會來說,深刻的理解這兩個面向對象的基本內容,對于盤活面向對象的抽象化編程思想至關重要。本文基本概況了接口和抽象類的概念、異同和使用規則,從學習的觀點來看,我認為這些總結已經足以表達其核心。但是,對于面向對象和軟件設計的深入理解,還是建立在不斷實踐的基礎上,Scott說自己每天堅持一個小時用來寫Demo,那么我們是不是更應該勤于鍵盤呢。對于接口和抽象類,請多用而知其然,多想而知其奧吧。
參考文獻:
(USA)Jeffrey Richter, Applied Microsoft .NET Framework Programming
總結
以上是生活随笔為你收集整理的[你必须知道的.NET] 第二回:对抽象编程:接口和抽象类的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: E宝YYDS!Epic发布免费PC端跨平
- 下一篇: 加油!大凉山娃全奖直博港中文 真少年用读