2010-09-07 97 views
0

爲了在類上執行某種「契約」,類應該總是實現一個接口嗎?什麼時候該類應該實現一個接口,什麼時候不應該接口?

當不應該一個類實現一個接口?

編輯:意思,什麼時候有一個類需要實現一個接口?爲什麼不讓一個班只有公共成員和私人成員具有不同的存取或設置功能?

(注意:不是在談論COM)

+2

什麼是「類接口」?類和接口在C#中是不同的東西。 – Oded 2010-09-07 20:07:04

+0

@Oded:我的措辭可能稍微偏離了一點,但我的意思是界面與班級聯繫在一起,我不知道表達該意義的正確方法 – Signal101 2010-09-07 20:07:50

+2

您是什麼意思我的「班級界面」。在c#中的類和接口是不同的,但相關的東西。 – 2010-09-07 20:07:52

回答

16

沒有,接口並不總是需要 - 類的公共成員已經構成合同。

當您希望能夠在兩者都提供類似功能時能夠交換一個類別時,該接口很有用。使用接口可以讓您將合同與具體實施分離。然而,這種解耦並不總是必要的或有用的。

.NET框架中的許多類都沒有實現任何接口。

+2

爲什麼你可能希望爲一個類創建一個接口而不打算爲其他具體類使用該接口的主要原因是單元測試。這對於幫助隔離依賴和stub/mock接口來注入刺激和/或感覺行爲通常很有用。 – 2010-09-07 20:54:26

4

僅在需要時才使用接口。
也就是說:當你想對某種抽象有不同的實現時。

當將來看起來最好爲某個特定的類提供一個接口(例如,因爲您希望爲同一個概念創建另一個實現),那麼您總是可以創建接口你現有的班級。 (ExtractInterface refactoring

+1

如果類具有足夠的「副作用」並且希望能夠在沒有副作用的情況下運行代碼,那麼有一個接口也是有幫助的。例如,假設您有一個帶有SelfDestruct()方法的設備類。您需要測試在合適的環境下(理想情況下在單元測試中,但也可能作爲集成測試的一部分),邏輯正確觸發'SelfDestruct()'。但是,您不希望實際上破壞原型。一個接口和適當的存根可以幫助你將代碼連接到一個更安全的類,這個類沒有連接到高爆炸物。 – 2010-09-07 22:08:50

1

這再一次歸結到他的意思是「界面」。術語接口和接口之間存在一些不明確之處。當使用術語接口時,它表示沒有方法聲明的對象。當使用術語接口時,這意味着您可以使用預先定義的一組函數(無論它們是否實現),並在必要時用您的邏輯覆蓋它們。一個例子是:

抽象類動物
類狗延伸動物

在這種情況下動物==接口(或合同),用於狗

接口可測量
類杯具可測量

在這種情況下,可測量的杯子接口

+0

好點。 C++中的Interace只是一個抽象類。 – 2010-09-07 20:18:16

1

您可能並不總是想的接口。考慮你可以用一個委託來完成類似的任務。在Java中,我將Runnable接口用於多線程應用程序。現在,我在.NET中編程,我非常依賴代表來完成我的多線程應用程序。本文有助於解釋代理與接口的需求。

When to Use Delegates Instead of Interfaces (C# Programming Guide)

委託提供多一點的靈活性,在Java中,我發現,我用C實現用一個函數指針的任何任務現在需要incasulation有一個接口。

雖然接口有許多情況。考慮IEnumerable,它被設計爲允許您遍歷各種集合,而不需要了解底層代碼如何工作。當需要爲另一個類交換一個類但需要一個類似的接口時,接口非常適合。 ICollection和IList提供了一組類似的功能來完成集合上的操作,而不用擔心具體情況。

如果您想更好地瞭解接口,建議您閱讀"Head First Design Patterns"

1

一個類不應該實現接口/ s,除非你想告訴你的程序的其他部分 - 「這個類可以做這些事情(但不指定它如何做它)」。
你想什麼時候這樣做?
例如,假設你有一個擁有動物的遊戲,並且說動物看到一個人時就會發出聲音(比如樹皮,吼聲等)。
如果所有的動物都會實現接口IMakeSound,其中有一個名爲MakeSound的方法,那麼您將不必關心應該發出這種聲音的是什麼類型的動物..您只需使用「 IMakeSound「動物的一部分,並稱之爲方法。
我應該補充說,當讀一個類聲明它實現了某個接口時,它會告訴他很多關於這個類的信息,這是另一個好處。

2

一個接口,這裏是指代碼構造而不是設計抽象,支持稱爲「鬆耦合」的代碼設計的基本原理。還有一些派生的原則可以告訴你代碼應該如何鬆散耦合,但是主要的,鬆散耦合有助於允許對代碼的更改影響儘可能小的代碼區域。

例如,考慮一些任意複雜度的計算。此計算由6個不同的類使用,因此爲了避免重複代碼,計算被封裝在自己的類Calculator中。這6個類都包含對計算器的引用。現在,假設你的客戶找到你,並說在計算器的一種用法中,如果滿足某些條件,則應該使用不同的計算。您可能會試圖簡單地將這兩個規則(使用規則和業務規則)和新的計算算法放入Calculator類中,但如果這樣做,那麼會發生兩件事情:首先,您可以讓Calculator瞭解其範圍之外的某些實現細節(如何使用它),以便它不需要知道,並且稍後可以再次更改。其次,使用Calculator的其他5個類,它們原樣工作得很好,因爲它們引用了已更改的類,因此必須重新編譯,並且必須進行測試,以確保您不會因爲更改某個類而破壞它們的功能爲第六班。

對此的「適當」解決方案是一個接口。通過定義一個接口ICalculator來暴露其他類所調用的方法,可以打破6類在具體類Calculator上的具體依賴。現在,6個類中的每一個都可以引用ICalculator。在這些課程中的5課中,您提供了他們一直使用並且工作得很好的相同Calculator類。 6號,你提供了一個特殊的計算器,知道附加規則。如果你從一開始就這樣做了,那麼你就不必碰其他5個班來改變到第6個班。

基本觀點是,類不應該知道它們依賴的其他對象的確切性質;他們應該只需要知道該對象會爲他們做些什麼。通過抽象對象從對象的東西中得出什麼,多個對象可以做類似的事情,而需要這些事情的類不需要知道差異。

鬆耦合以及「高內聚」(對象通常應該是知道如何做一個小的,高度相關的任務的專家),是大多數您將看到的軟件設計模式的基礎隨着你進入軟件開發理論。

與一些答案相反,有一些設計方法(例如SOLID)指出,應始終將依賴關係設置爲抽象類,如抽象基類或接口,並且絕不要讓一個類依賴另一個具體類類。這裏的邏輯是,在商業軟件開發中,應用程序的初始需求是非常小的,但如果不是保證,這是一個安全的假設,即一組需求將會增長和變化。當發生這種情況時,軟件必須增長。根據嚴格的設計原則創建更小的應用程序允許擴展軟件,而不會導致設計不當的大問題(帶有大量代碼的大類,以不可預知的方式影響其他類的類變化等)導致的問題。然而,軟件開發的藝術以及時間和金錢的約束使得你可以(而且必須)很聰明,並且「根據我所知道的這個系統將會增長的方式,這是一個需要的領域要精心設計,以便適應,而這部分幾乎肯定不會改變「。如果這些假設發生了變化,那麼您可以回過頭來重新構建您設計的代碼區域,以便在擴展該區域之前更加健壯。但是,在第一次實施代碼後,您必須願意並且能夠返回並更改代碼。

相關問題