2009-12-19 122 views
4

所以你有一個接口和一個抽象類,它實現了接口中方法的一個子集。您還有一些類繼承了抽象類,並給出了抽象類不提供的方法的實現。java中的抽象類和接口最佳實踐

那麼這裏最好的做法是什麼?我正在討論的問題如下:

1)抽象類應該實現接口還是應該實現其子類?應該每班上課嗎?在我看來,只有抽象類應該。當然,所有的類都可以實現這個接口,但這似乎是多餘的,因爲抽象的孩子會繼承接口,因爲它們擴展了抽象類。 2)鑑於抽象類實現了接口的一部分,它是否也爲其未實現的方法聲明瞭抽象方法?在我看來,這是對的,但從某種程度上看,這似乎是多餘的,因爲抽象的孩子們需要實施這些方法才能編譯。

那麼你最好的做法是什麼?問題歸結爲:我們有一個接口來定義我們想要某些類所做的事情,我們在接口中定義了一些方法的子集來定義常見行爲,並且我們有幾種不同的方法來定義非常見的行爲。解決這個問題的最好方法是什麼?

回答

2

抽象類應該實現接口,並提供通用成員函數的具體實現。 IIRC不需要爲它沒有實現的元素聲明抽象方法,因爲這些被假定需要由子類實現。

8

在這裏應該幫助你的原則DRY:不要重複自己(http://en.wikipedia.org/wiki/Don%27t_repeat_yourself)。

在這種情況下,DRY意味着你不應該做不必要的工作。

因此,對於第一個問題,抽象類應該實現接口,因爲它可以避免在每個具體類上重複「實現X」子句。

至於第二個問題,在實現它的抽象類中重複接口方法沒有意義。這是多餘的工作。此外,當界面發展/變化時,您需要更改抽象類中的對應(抽象)方法,這很令人頭疼。在某些時候,你會錯過更新某些方法,具體的類將需要實現這些徒勞無功。

+0

+1,我會補充一點,如果我親眼看到一個實現了Foo的具體類,並且擴展了AbstractFoo,那麼我的第一個直覺就是Foo和AbstractFoo甚至可能沒有關係。隨着名字變得不那麼明顯,更多地引起混淆。 – PSpeed 2009-12-19 08:42:05

+1

接口並不意味着進化和改變... – TofuBeer 2009-12-19 09:30:13

+0

程序發展(因爲您添加新功能,修復錯誤,無論如何),這會導致底層構件(類,接口,方法...)發生變化。例如,你可能會決定一個方法需要一個額外的參數,所以你必須在聲明界面中改變它的簽名。 – 2009-12-19 10:11:29

0

您是否比抽象類或其子類有更多的接口實現?你的設計需要界面嗎?否則,界面對你的設計沒有任何貢獻,我建議你簡單地擺脫它。

當涉及到明確的問題時,抽象類應該實現接口。擴展抽象類的類不應該。

您不應該在已經存在於接口中的抽象類中冗餘地聲明抽象方法。

2

最靈活的方式來對這個方案是:

  1. 提供接口
  2. 提供一個實現該接口
  3. 提供的具體的類,要麼從抽象類延伸或擴展抽象類從另一個類並實現接口
  4. 一直(除非你不能)將變量/參數/常量聲明爲接口而不是抽象類或具體類

使具體類實現接口沒有意義(稍後)。 抽象類從接口重複抽象方法沒有意義。

通過#4確保實現接口的所有類都可以使用 - 如果要使用抽象類,則不能使用實現接口但不擴展抽象類的類。

(後期)

爲具有抽象類和具體類實現該接口的一個說法是,如果你要在以後更改具體類不再擴展抽象類,那麼你可以忘了也實現了這個接口,在某些情況下,這個接口可能會破壞代碼而不會引起編譯器的抱怨。我不知道我對這個觀點的看法。

1

接口方法是隱式抽象的,所以如果一個抽象類實現一個接口,就不需要滿足抽象類中的接口契約。抽象接口在技術上是合法的,但也是多餘的。只要所有子類都要實現接口,抽象類就可以實現接口,但抽象類不應該包含已實現的方法。

接口方法是特定於實現(對於實現類是唯一的),而抽象狀態和行爲是普遍的,或者在實現中共享。將接口方法作爲通用功能來實現將是一個矛盾。

關鍵問題是您打算如何使用接口實現?如果基本接口除了定義一個附加約定之外沒有用於其他任何東西,我會說簡單地將抽象方法添加到抽象類中,否則接口是冗餘開銷。如果你發現一個你想要訪問接口方法的用例,但不一定是通用的功能,那麼接口可能是值得的。