2016-07-13 111 views
0

定義接口,在基本抽象類中實現接口,給它默認行爲並從基類繼承是好習慣嗎?接口和基本抽象類c#

還是那種矯枉過正?

+0

取決於您嘗試實現的內容...接口使您能夠在合同上進行中繼,以便您可以在不修改所有代碼的情況下更改實現。基類對描述默認行爲很有用。 – Thomas

回答

4

是否使用接口或抽象類是兩個完全不同的問題。可能發生的兩個答案都是,但其中一個與另一個無關。

除非您完全確定您需要多個從基類繼承並共享某些方法的類,否則我不會計劃使用繼承。當我們開始設想一些完美的課本級別時,它往往會變得複雜並且無法實現。當你重構或者你發現自己寫了一個類似的類並且不想重複代碼時,它通常會更有意義。

編寫一個接口然後實現它是一個很好的習慣,當你創建另一個類將要依賴的東西時(這是很常見的)。例如,如果你知道你的類將依賴於另一個「做些什麼」的課,那麼你可以暫時停下第一課的工作來編寫界面,並完成第一課,這取決於IDoesSomething。你還沒有弄清楚實現是什麼,但這並不重要,因爲你已經編寫的類只依賴於接口。 (控制反轉 - 好的做法。)然後你可以編寫一個實現IDoesSomething的類。

只是用一個例子來說明。假設我正在寫一個類,它提供了一個Menu對象包含MenuItem對象的嵌套列表:

public class MenuProvider 
{ 
    public Menu GetMenu(string menuId) 
    { 
     //code that gets the menu 
     return menu; 
    } 
} 

然後我意識到,我會需要返回之前過濾掉某些菜單項。這可能基於配置設置,特定用戶或其他任何東西。

我可能會寫這個接口:

public interface IMenuFilter 
{ 
    void FilterMenu(Menu menu); 
} 

,然後修改我的原班這樣的:

public class MenuProvider 
{ 
    private readonly IMenuFilter _menuFilter; 

    public MenuProvider(IMenuFilter menuFilter) 
    { 
     _menuFilter = menuFilter; 
    } 

    public Menu GetMenu(string menuId) 
    { 
     //code that gets the menu 

     //filter the menu 
     _menuFilter.FilterMenu(menu); 
     return menu; 
    } 
} 

我不知道是什麼的IMenuFilter的實施將是。在實踐中,它最終可能是一組單獨的類的組合,每個類都執行一種類型的過濾。但重要的是,我不需要停止我在MenuProvider上做的事情就可以搞清楚。我可以寫這個類,甚至用模擬的IMenuFilter來測試它,然後繼續編寫該過濾器的細節。

+0

感謝Scott的回覆! – MaitlandMarshall

2

你有共同的功能,你想在這個接口的實現之間共享?如果是這樣,那麼創建一個抽象基類。否則,現在不用擔心。您可以隨時添加一個。但編程接口幾乎總是一個好主意。

1

通常,您將使用或者的一個接口繼承。我通常不會同時使用這兩個班級。

當您想從基類繼承功能時使用繼承。

當您希望不同的類實現某些相同的核心功能但不一定共享代碼時使用接口。

+2

我個人不同意這一點。我認爲在複雜的情況下,完全合理的做法是在接口上編寫消費者代碼,同時保持抽象基類的層次結構,以保持具體實現的乾爽。 –

+0

一個真實的例子:針對'IOutputController'的非抽象實現的軟件查詢插件程序集(使用反射)。插件(由主應用程序以外的人編寫)實現此接口。它們可以自由地繼承各種ABCs,比如'OutputControllerBase','SerialOutputControllerBase'或'ParallelOutputControllerBase',它們由主應用程序提供。但是,因爲他們只需要實現'IOutputController',所以它們可以自由地從所有這些中繼承。 –

+1

我也不同意這一點。建議我們通常不使用抽象類的接口表明一個接口與另一個接口有關。接口將合同與實施分離。那麼,爲什麼我們期望包含抽象類的實現是* only *實現?我們可能經常有多個實現的接口,只有一些涉及抽象類。另外,接口與類共享功能無關。它們可以讓實現沒有共同的功能。 –