前言:最近一個認識的朋友準備轉行做程式設計,看他自己邊看視訊邊學習,挺有幹勁的。那天他問我接口和抽象類這兩個東西,他說,既然它們如此相像, 我用抽象類就能解決的問題,又整個接口出來幹嘛,這不是誤導初學者嗎。部落客呵呵一笑,回想當初的自己,不也有此種疑惑麼。。。今天打算針對他的問題,結合一個實際的使用場景來說明下抽象類和接口的異同,到底哪些情況需要用接口?又有哪些情況需要用抽象類呢?
C#基礎系列目錄:
<a href="http://www.cnblogs.com/landeanfen/p/4636102.html" target="_blank">C#基礎系列——Linq to Xml讀寫xml</a>
<a href="http://www.cnblogs.com/landeanfen/p/4632467.html" target="_blank">C#基礎系列——擴充方法的使用</a>
<a href="http://www.cnblogs.com/landeanfen/p/4627383.html" target="_blank">C#基礎系列——序列化效率比拼</a>
<a href="http://www.cnblogs.com/landeanfen/p/4642814.html" target="_blank">C#基礎系列——反射筆記</a>
<a href="http://www.cnblogs.com/landeanfen/p/4642819.html" target="_blank">C#基礎系列——Attribute特性使用</a>
<a href="http://www.cnblogs.com/landeanfen/p/4642820.html" target="_blank">C#基礎系列——小話泛型</a>
<a href="http://www.cnblogs.com/landeanfen/p/4704139.html" target="_blank">C#基礎系列——多線程的常見用法詳解</a>
<a href="http://www.cnblogs.com/landeanfen/p/4642848.html" target="_blank">C#基礎系列——委托和設計模式(一)</a>
<a href="http://www.cnblogs.com/landeanfen/p/4710174.html">C#基礎系列——委托和設計模式(二)</a>
<a href="http://www.cnblogs.com/landeanfen/p/4721525.html" target="_blank">C#基礎系列——再也不用擔心面試官問我“事件”了</a>
<a href="http://www.cnblogs.com/landeanfen/p/4734252.html" target="_blank">C#基礎系列——異步程式設計初探:async和await</a>
部落客打算使用原來在華為做外包的時候一個場景:我們針對華為裡面的裝置做了一個采集裝置使用率的程式,裝置的類型很多,各種裝置的登入和登出方式基本相同,但是每種裝置的采集的規則又不太相同。大緻的場景就這樣,我們來看代碼吧。
根據業務場景,我們簡單搭建代碼,先來看看代碼結構圖:

ESTM.Spider:項目的入口程式,隻為測試,這裡就簡單用了一個控制台程式。
ESTM.Spider.Huawei:華為裝置采集規則,定義接口抽象實作和具體實作。
ESTM.Utility:解決方案的工具類和接口。
下面來看看具體的實作代碼:
這是一種比較典型的應用場景。接口定義規則,抽象類定義公共實作或者抽象方法,具體子類實作或者重寫抽象類方法。我們重點來看這裡的中間橋梁——抽象類。我們知道,抽象類裡面既可以有實作的方法,也可以有未實作的抽象方法。
(1)在這裡,Login、LoginOut方法由于子類是通用的具有相同邏輯的方法,是以我們需要在抽象類裡面去實作這兩個方法,如果子類沒有特殊需求,調用的時候直接用父類的方法就好了; 如果子類有特殊需求,可以override父類的方法。這樣設計既提高了代碼的複用率,也可以靈活複寫。
(2)另一方面,抽象類裡面也定義了抽象方法,這個抽象方法在這裡的作用就很好展現了:如果子類不重寫父類的抽象方法,編譯通不過,直接報錯。這樣就要求我們子類必須要重寫抽象方法。從這點來說,抽象方法和接口的方法申明差別不大。
(3)如果這裡不用抽象類,就用一個普通的類來代替行不行?部落客的答案是:行!但不好!如果你非要說,我用一個普通的類,将public abstract string Spider(Device oDevice);這個方法寫成
貌似也沒問題,反正子類要重寫的。确實,這樣設計沒問題,但是如果你不慎子類忘了override呢?程式還是會跑起來,運作的時候可能會報錯。微軟既然給我們提供了abstract這麼一個東西,我們為什麼不用呢。
以上我們抽象類使用的必要性和使用方法是介紹完了。那麼接下來新的問題來了,可能就有人問了,你上面說了叭叭叭說了這麼多,無非就是說了抽象類的必要性,那麼既然抽象類這麼有用,我們直接用抽象類就好了,你幹嘛還要弄一個接口呢。談到這裡,就要說到面向接口程式設計。其實,面向接口程式設計和面向對象程式設計并不是平級的,它并不是比面向對象程式設計更先進的一種獨立的程式設計思想,而是附屬于面向對象思想體系,屬于其一部分。或者說,它是面向對象程式設計體系中的思想精髓之一。而之前部落客的文章就分享過面向接口程式設計的意義所在:依賴倒置,松耦合。那麼這裡是否可以不要接口,直接用抽象類代替呢?答案還是行!但不好!
比如我們現在又來了新的需求,中興也要用我們的采集系統,但是它的裝置類型、登入登出方式和華為裝置差別非常大。那麼這個時候我們接口的意義就展現了,如果我們使用接口,我們隻需要再重寫一個ESTM.Spider.Huawei這個項目就好了,我們暫且命名叫ESTM.Spider.Zhongxing。我們來看看:
代碼如下:
由于這裡采用了接口,我們将ESTM.Spider.Zhongxing這個項目開發完成後生成dll,将dll放到控制台程式中,直接通過MEF導入不同的子類對象就可以使用,不需要更改控制台裡面的大部分東西。如果不用接口,而是直接用抽象類代替,那麼控制台裡面大部分的代碼都得改,并且控制台程式依賴多個dll,對設計的松耦合也不利。部落客這裡為了簡單,用了MEF來簡單導入,其實正式項目中,應該是用工廠采用反射直接建立出具體的執行個體。
1、接口是一組規則的集合,它主要定義的是事物的規則,展現了是這種類型,你就必須有這些規則的概念。它的目的主要是依賴倒置和松耦合,從這點來說,接口不能省掉或者用抽象類代替。總而言之,接口和抽象類不可同日而語。
2、抽象類主要用于公共實作和限制子類必須重寫。以上面的例子說明,Login、Loginout用于公共實作,提高了代碼複用,Spider用于抽象,限制子類必須要重寫Spider方法。這也就是這裡不能用普通類的原因。
3、用一句話概括接口和抽象類的差別:使用抽象類是為了代碼的複用,而使用接口的動機是為了實作多态性(依賴倒置)。至于使用的時候到底是用接口還是抽象類,看具體的情況。
本文轉自懶得安分部落格園部落格,原文連結:http://www.cnblogs.com/landeanfen/p/4953025.html,如需轉載請自行聯系原作者