2016-05-17 66 views
1

我有一個名爲IRepository的Data Repository接口。 BakerRepository從中繼承了通用的CRUD方法。現在對於BakerRepository,它可能有一些對自己來說很特殊的方法。例如,一種稱爲Bake的方法。在C#中將父接口轉換爲子接口時,依賴注入模式的目的是否會丟失?

我正在使用Unity.Mvc作爲依賴項的容器。這是我最初是如何使用它的控制器,這是我從我前幾天看了教程中學:

private IRepository<Baker, int> _repository; 

public BakersController(IRepository<Baker, int> repo) 
{ 
    _repository = repo; 
} 

容器將基本上給我BakerRepository實施。但是,當我嘗試使用唯一的Bake方法時,它會返回錯誤,因爲_repository的類型爲IRepository<Baker, int>,因此不知道Bake方法。

所以,我想這個實現,而不是:

private BakerRepository _repository; 

public BakersController(IRepository<Baker, int> repo) 
{ 
    _repository = repo as BakerRepository; 
} 

我不完全瞭解DI模式,我只使用它,因爲我學會了它作爲一個關於ASP數據倉庫教程的一部分.Net MVC。我讀了它,我認爲它實際上是一個很好的設計模式,所以我決定繼續使用它,儘管我沒有百分之百地獲得它。

現在我想知道如果我這樣做的實現,如果我的目的依賴注入無用。我不太瞭解DI模式,我在其他地方找不到確切的答案。

+0

要使用IRepository執行Bake方法,您可以在IRepository中使用Reflection或定義一個類型爲Action的屬性。通過反射,如果存在方法並且可以直接執行「操作」,則可以調用方法。但是如果你知道你需要調用Bake方法,爲什麼你要通過'IRepository'? –

+2

這個具體的問題與DI無關,而與一般的抽象無關。您正在使用接口(抽象)以便不與特定的實現(通常,爲了更簡單的單元測試和「swapability」)相聯繫。對我來說,聽起來更像是你希望'Bake()'方法成爲'Baker'的一部分,而不是'IRepository'(它應該只用持久性而不是邏輯來打擾自己)。 – haim770

+0

我會說你不會失去DI的積極方面。 DI模式只是一種方法,用於將實現方面的控制從類內部轉換爲外部(您也可以這樣做),以便在不知道注入對象的類的實現的情況下更改實現。注入自動化的可能性是提供更好資源分配的另一個積極方面。 - 對不起有點慢打字;-) –

回答

4

在構造鑄造IRepository<Baker, int>BakerRepository違反至少兩個出5個SOLID原則:

  • Open/Closed Principle被違反,因爲這將導致改變系統(的更換或裝飾的不同部分例如存儲庫)在整個系統中引起徹底的更改,因爲您可能在許多地方使用BakerRepository
  • Interface Segregation Principle很可能違反了,因爲您的BakersController不太可能使用全部BakerRepository方法。
  • Dependency Inversion Principle被違反,因爲你的BakersController直接取決於具體類型,而不是抽象。這使得獨立更改和演進實施變得更加困難。

通過將IRepository<Baker, int>參數更改爲BakersRepository,都無法解決這些問題。相反,你應該打破這種特殊Bake方法,並把它背後自身的抽象,例如:

public interface IBakeHandler 
{ 
    BakeResults Bake([parameters]); 
} 

可以標記BakeRepository這個新IBakeHandler接口,以及:

class BakeRepository : IRepository<Bake>, IBakeHandler 
{ 
} 

這使得你讓BakeController取決於IBakeHandler代替:

private IBakeHandler _bakeHandler; 

public BakersController(IBakeHandler bakeHandler) 
{ 
    _bakeHandler = bakeHandler; 
} 

這可以防止VIO SOLID原則,因爲:

  • 用代理,裝飾器或適配器替換實現不會影響整個系統; BakerController不受這種變化影響。
  • IRepository<T>尤其是IBakeHandler保持狹窄,使創建裝飾器以應用橫切關注點或爲測試創建模擬/存根/假實現變得更容易。
  • 可以將存儲庫和IBakeHandler實現置於裝有控制器的程序集未引用的程序集中。

請注意,儘管每當您打開此類存儲庫實現以添加新功能時,您都會有效地違反開放/封閉原則以及可能的單責任原則。

如果您有許多「額外」存儲庫功能,您將會看到許多單方法接口,如IBakeHandler。一旦你看到這種情況發生,從這些接口中提取新的通用抽象。您可以應用衆所周知的模式,如描述爲herehere

+0

你好,謝謝你的回答。我只是有跟進問題。你的意思是'BakerRepository'應該從'IBakeHandler'而不是'IRepository'繼承? 「BakerRepository」的IRepository的實現情況如何? – christianleroy

+0

@prinzechristian我在說BakerRepository可以實現IRelository和IBakeHandler。查看我的更新。 – Steven

0

正確的答案是實際將BakerRepository傳遞給BakerController,因爲這取決於它。

正如你所說,依賴注入是一個非常有用的模式。但是,它只是一個工具,用於在您正確提取類的依賴關係時幫助構建對象。在非框架設置中,您將負責構建這些對象,並且您很快就會厭倦大量的參數傳遞。 DI可以幫助你。但它是可選的。所以,如果你手動完成,你總是會建立一個BakerController傳入的BakerRepository。因此,當你使用DI時,同樣的邏輯也適用。

+2

我同意第一部分,但你似乎在第二段中將DI與IoC容器混淆。你不需要容器來做DI。 –

0

直接回答你的問題。你可以提升你的依賴性,但這對我爲你做的事情沒有任何影響。

打破了你的依賴,可以用於TDD也是有用的,你隔離外部依賴允許類的單元測試,而不執行相對昂貴的I \ 0話費或破壞性的電話。

而且打破了依賴關係可以拍攝對象的做一件事的責任和有對象。

在實踐中我很少見過或用過d \ I(實施關閉的IOC容器的背面)改變的具體實現,已經只是做了最近的功能切換

另一點是,它不是對象外部的I \ 0可能會被啓發並且仍然可以通過社交或孤獨的方式進行測試。

你不應該是D \ I的一切....