2008-12-09 78 views
38

從我讀過的最佳實踐中可以看出,基於接口的類和鬆散耦合的對象有助於代碼的重用和單元測試。每一個對象都應該有一個接口,並且所有對象都是鬆散耦合的?

這是否正確,是否應該始終遵守規則?

我問的原因是我最近在一個有100個非常不同的對象的系統上工作。幾個共享的通用接口,但大多數不接受,並懷疑它是否應該有一個接口鏡像這些類中的每個屬性和功能?

我正在使用C#和點網2.0但是我相信這個問題會適合多種語言。

+0

正確的,你應該。左邊,你應該有一個發電機爲你做「樣板」。 – Pacerier 2012-03-06 05:21:15

回答

52

對於真正提供服務的對象(認證,存儲等)非常有用。對於沒有任何進一步依賴性的簡單類型,以及從未有任何替代實現的地方,我認爲可以使用具體類型。

如果你遇到這樣的事情,你最終會花費很多時間嘲弄/扼殺世界上的所有東西 - 這往往會導致脆弱的測試。

13

不是。服務組件(爲你的應用程序做事的類)非常適合用於接口,但是作爲一個規則,我不會爲諸如基本實體類的接口打擾。

例如: 如果您正在開發一個領域模型,那麼該模型不應該是接口。但是,如果該域模型想要調用服務類(如數據訪問,操作系統函數等),那麼您應該查看這些組件的接口。這減少了類之間的耦合,並且意味着它是接口,或者是耦合的「契約」。

在這種情況下,你開始發現編寫單元測試要容易得多(因爲你可以有數據庫訪問等的存根/嘲笑/假貨等),並且可以使用IoC來交換組件,而無需重新編譯應用程序。

8

我只會使用需要抽象級別的接口 - 即您需要使用多態行爲。常見的例子是依賴注入,或者你有一個工廠類型的場景,或者你需要建立一個「多重繼承」類型的行爲。在我的情況下,以我的開發風格,這是非常經常的(我喜歡聚合深度繼承層次結構,除了UI控件以外的大多數事情),但我已經看到使用非常少的非常好的應用程序。這一切都取決於...如果你確實大量使用接口,請注意Web服務。如果您需要通過Web服務公開您的對象方法,那麼它們不能真正返回或採用接口類型,只能使用具體類型(除非要手動編寫所有自己的序列化/反序列化)。是的,這已經讓我大傷腦筋......

3

當你想明確定義軟件兩個不同部分之間的交互時,應該使用接口。尤其是當您想要拆分連接的任一端並將其替換爲其他端口時。

例如在我的CAM應用程序中,我有一個連接到Points集合的CuttingPath。由於在我的應用程序中,CuttingPaths總是由Points組成,所以擁有IPointList接口是沒有意義的。

但是我使用接口IMotionController與機器進行通信,因爲我們支持許多不同類型的切割機,每個切割機都有自己的指令集和通信方法。所以在這種情況下,將其放在界面後面是有道理的,因爲一個安裝可能使用另一個不同的機器。

我們的應用程序自80年代中期以來一直保持並於90年代後期轉向面向對象設計。我發現可能會發生什麼變化大大超過了我原先認爲的和接口的使用增長。例如,它曾經是我們的DrawingPath由點構成的。但現在它由實體(樣條曲線,弧,ec)組成,因此它指向一個EntityList,它是實現IEntity接口的Object的集合。

但是,這種變化是通過認識到DrawingPath可以使用許多不同的方法來繪製的。一旦意識到需要多種繪圖方法,那麼就需要一個接口而不是與一個實體對象的固定關係。

請注意,在我們的系統中,DrawingPaths被渲染爲低級別的切割路徑,這些切割路徑始終是一系列點分段。

1

我同意kpollock。接口用於獲得物體的共同點。它們可用於IOC容器和其他用途的事實是一個附加功能。

比方說,您有幾種類型的客戶類略有差異,但具有共同屬性。在這種情況下,擁有一個ICustomer接口將它們綁定在一起非常棒,logicaly。通過這樣做,您可以創建類似於ICustomer對象的類/方法,而不是爲每個客戶變體創建一個handerl方法。

這是接口的優勢。 如果你只有一個實現接口的類,那麼接口沒有多大的幫助,它只是坐在那裏,什麼也不做。

5

接口的缺點是它們不能被版本化。一旦您發佈界面,您將不會對其進行更改。如果您使用抽象類,那麼您可以通過添加新方法並將它們標記爲虛擬來輕鬆地延長合同。

作爲一個例子,.NET中的所有流對象都是從System.IO.Stream派生的,它是一個抽象類。這使得微軟很容易添加新功能。在frameworkj的第2版中,他們在不破壞任何代碼的情況下添加了ReadTimeoutWriteTimeout屬性。如果他們使用了一個接口(比如IStream),那麼他們將無法做到這一點。相反,他們不得不創建一個新的界面來定義超時方法,如果我們想使用這個功能,我們必須編寫代碼來有條件地投射到這個界面。

+1

接口繼承是允許的。這不會完成同樣的事情嗎? – 2012-03-06 08:11:58

+0

你說得很好,肖恩,但我有和湯姆一樣的問題。如果他們發佈了「IStream2:IStream」,會發生什麼?一團糟?你能詳細說明嗎? – toddmo 2015-03-14 23:06:17

2

我試圖從最近的項目上直接接受'代碼到接口'的建議。最終結果基本上是在一個接口(大I)實現中重複每個類的公共接口(小i)。這在實踐中是毫無意義的。

一個更好的策略,我覺得是你的限制接口實現對動詞

Print() 
Draw() 
Save() 
Serialize() 
Update() 

...等等等等,這意味着類,它們的主要作用是存儲數據 - 如果你的代碼精心設計的他們通常只會這樣做 - 不想或不需要接口實現。任何你可能想要的運行時配置行爲,例如代表相同數據的各種不同的圖形樣式。

當事情要求工作真的不想知道工作是如何完成的時候更好。這意味着你可以給它一個macguffin,它可以簡單地信任它會做任何公共接口說它做,並讓有問題的組件簡單地選擇做這項工作。

相關問題