2010-11-09 78 views
6

當你使用依賴注入時,你注入哪些依賴關係?我應該注入哪些依賴關係?

我以前注入所有依賴性但這樣做當TDD已經發現通常有兩種類型的相關性:

  • 那些其可以例如改變真正外部依賴ProductRepository
  • 純粹爲了可測試性而存在的那些例如在已提取並注入只是可測性

一種方法的類的行爲的部分原因是注入所有依賴這樣

public ClassWithExternalDependency(IExternalDependency external, 
    IExtractedForTestabilityDependency internal) 
{ 
    // assign dependencies ... 
} 

但我發現這可能會導致依賴性膨脹的DI註冊表。

另一種方法是隱藏「可測性依賴」這樣

public ClassWithExternalDependency(IExternalDependency external) 
    : this (external, new ConcreteClassOfInternalDependency()) 
{} 

internal ClassWithExternalDependency(IExternalDependency external, 
    IExtractedForTestabilityDependency internal) 
{ 
    // assign dependencies ... 
} 

這是更多的努力,但似乎使很多更有意義。缺點是不是所有對象都在DI框架中配置,因此打破了我所聽到的「最佳實踐」。

你會主張哪種方法,爲什麼?

回答

1

我相信你最好注入所有的依賴關係。如果它開始變得有點笨拙,那可能表明您需要稍微簡化一些東西,或者將依賴關係移動到另一個對象中。感覺你的設計「痛苦」,你可以真正啓發。

至於註冊表中的依賴性膨脹,您可能會考慮使用某種傳統的綁定技術,而不是手動註冊每個依賴項。一些IoC容器具有內置於其中的基於約定的類型掃描綁定。例如,下面是我在使用Ninject一個卡利WPF應用程序中使用的模塊的一部分:

public class AppModule : NinjectModule 
{ 
    public override void Load() 
    { 
     Bind<IShellPresenter>().To<ShellPresenter>().InSingletonScope(); 

     BindAllResults(); 
     BindAllPresenters(); 
    } 

    /// <summary> 
    /// Automatically bind all presenters that haven't already been manually bound 
    /// </summary> 
    public void BindAllPresenters() 
    { 
     Type[] types = Assembly.GetExecutingAssembly().GetTypes(); 

     IEnumerable<Type> presenterImplementors = 
      from t in types 
      where !t.IsInterface 
      && t.Name.EndsWith("Presenter") 
      select t; 

      presenterImplementors.Run(
       implementationType => 
        { 
         if (!Kernel.GetBindings(implementationType).Any()) 
          Bind(implementationType).ToSelf(); 
        }); 
    } 

即使我有幾十個結果和主持人跑來跑去的,我沒有額外的註冊工作。

0

我當然不會注入所有的依賴關係,因爲要停止?你想注入你的string依賴關係嗎?我只反轉了單元測試所需的依賴關係。我想存根數據庫(例如見this example)。我想存根發送電子郵件。我想存根系統時鐘。我想要寫入文件系統。

儘可能多地反轉儘可能多的依賴關係,甚至那些不需要測試的依賴關係,就是讓單元測試變得越困難,越是殘缺不全,就越能真正測試系統的行爲。這使得你的測試更不可靠。它也使應用程序根目錄中的DI配置複雜化。

+1

反轉依賴關係的好處之一是能夠單獨測試單元。我可能會提取一個計算器類來單獨測試它,但也許它不需要注入(參見第二個代碼示例)。我無法在原地進行測試,因爲它會使計算器課程的客戶端的測試膨脹。 – Alex 2011-01-05 20:30:24

+1

注射所有注射劑,新的所有新劑型。如果沒有這種區分,DI將要求所有物體在整個程序期間生活。 Newables,又名值類型,表示惰性數據和可選的一些相關的轉換行爲(即接受值並返回新值的方法)。注射劑,又名服務/業務類型,代表功能和可選的一些相關的程序狀態。可以說,我們也有I/O類型來表示外部狀態,例如文件()。 I/O類型必須是新的,但應通過抽象工廠創建,以便可以進行模擬測試。 – Jegschemesch 2014-04-17 19:12:53

0

我會手工連接所有非外部依賴關係並僅「註冊」外部依賴關係。當我說非外部的時候,我的意思是屬於我的組件並且爲了單一責任/可測試性而被提取出來的對象,我永遠不會有這樣的接口的任何其他實現。外部依賴包括數據庫連接,Web服務,不屬於我的組件的接口。我會將它們註冊爲接口,因爲它們的實現可以切換到stubbed集成測試。在DI容器中註冊少量組件使得DI代碼更易於閱讀和擴展。

相關問題