2008-11-18 50 views
6

比方說,我們有構造函數注射和默認的重載

public interface ITimestampProvider 
{ 
    DateTime GetTimestamp(); 
} 

和消耗它

public class Timestamped 
{ 
    private ITimestampProvider _timestampProvider 

    public Timestamped(ITimestampProvider timestampProvider) 
    { 
     // arg null check 

     _timestampProvider = timestampProvider; 
    } 

    public DateTime Timestamp { get; private set; } 

    public void Stamp() 
    { 
     this.Timestamp = _timestampProvider.GetTimestamp(); 
    } 
} 

和的默認實現類:

public sealed class SystemTimestampProvider : ITimestampProvider 
{ 
    public DateTime GetTimestamp() 
    { 
     return DateTime.Now; 
    } 
} 

它是有益還是harfmful介紹這個構造函數?

public Timestamped() : this(new SystemTimestampProvider()) 
{} 

這是一個普遍的問題,即時間戳不是有趣的部分。

+0

CAB使用什麼樣的依賴注入風格?城堡? – 2008-11-18 22:00:52

+0

就這個問題而言,沒有。這是一個通用的API查詢。我已經更新了這個問題,以消除「注入」的內涵。 – 2008-11-18 22:09:34

回答

7

我認爲這取決於場景,基本上是消費者代碼是誰(庫與應用程序)以及您是否使用IoC容器的功能。

  • 如果您使用的是IoC容器,這是不是公共API的一部分,然後讓容器做繁重的,只是有一個構造函數。添加無參數構造函數只會讓事情混亂,因爲你永遠不會使用它。

  • 如果這是公共API的一部分,則保留兩者。如果您使用IoC,只要確保您的IoC找到「最貪婪」的構造函數(具有最多參數的構造函數)。不使用IoC的人們,但使用你的API將不會爲了使用你的對象而構建整個依賴圖。

  • 如果您不使用IoC容器,但只想用模擬進行單元測試,請保留無參數構造函數,並將貪婪構造函數置於內部。爲你的單元測試程序集添加InternalsVisibleTo,以便它可以使用貪婪的構造函數。如果你只是單元測試,那麼你不需要額外的公共API表面。

4

我不會提供的構造函數。這樣做可以很容易地調用新的TimeStamped,並在您的IoC可能配置爲使用OtherTimestampProvider()時使用新的SystemTimestampProvider()獲取實例。

一天結束時,你會用的時間試圖調試爲什麼你得到了錯誤的時間戳地獄結束。

如果你只提供第一個構造函數,你可以簡單地找到SystemTimestampProvider的用法來找出誰是(錯誤地)使用該提供者而不是IoC配置提供者。

+0

雖然IoC不是這裏場景的一部分,但我假設大多數實現將注入提供者,否則使用默認構造函數,這意味着如果不覆蓋`ITimestampProvider`,則只會獲得`SystemTimestampProvider`,意圖。 想法? – 2008-11-22 02:30:52

3

總的來說,我不這麼認爲...這取決於你使用依賴注入什麼。當我使用DI進行單元測試時,當注入的實例爲空時,通過實例化依賴對象的生產版本來做同樣的事情(或多或少)...然後我有一個不帶參數的重載,並且委託到那個...我使用無參數的生產代碼,併爲單元測試方法注入一個測試版本...

如果你在談論IOC容器應用程序,otoh,你需要小心在什麼配置設置告訴容器的方式,目前還不清楚這樣做干擾......

public class EventsLogic 
    { 
     private readonly IEventDAL ievtDal; 
     public IEventDAL IEventDAL { get { return ievtDal; } } 

     public EventsLogic(): this(null) {} 
     public EventsLogic(IIEEWSDAL wsDal, IEventDAL evtDal) 
     { 
      ievtDal = evtDal ?? new EventDAL(); 
     } 
    } 
0

我會盡量避免這一點 - 有在那裏我發現它是一個幾個地方有用的設計,但更經常的t但我沒有發現它只是導致我犯了一些令人費解的錯誤。在DI容器可以確保您始終獲得,你可以用一個具體的實例 -

需要對默認注入的對象是通過使用依賴注入容器(我用StructureMap)來管理所有的佈線大大降低。

在那裏我仍然想使用你的建議構造函數中的唯一的地方是我的單元測試,但最近我已經得到了使用假或嘲笑的對象遠遠更大的價值。

有些地方具有默認的依賴對象是正確和有用的設計,但一般我會說,你是剛剛推出,不增添了不少價值緊密結合。

0

這既沒有幫助也沒有害。它提出了一個美學問題,因爲只有當您的設計允許屬性設置器注入時,纔將DI限制爲構造器注入。

另一種選擇是實現一個返回默認實現一個getter:

public DateTime Timestamp 
{ 
    get { return _timestampProvider??new SystemTimestampProvider(); } 
    set { _timestampProvider = value; } 
} 

此外,還可以使用單,如果你擔心在堆中創建過多的對象實現了上述。

0

我的團隊使用這種方法取得了很大的成功。我推薦一個更改:
使_timestampProvider只讀。這迫使提供者在構建時確定性並消除錯誤。

public class Timestamped 
{ 
    private readonly ITimestampProvider _timestampProvider; 

    public Timestamped(ITimestampProvider timestampProvider) 
    { 
     _timestampProvider = timestampProvider; 
    } 

    public Timestamped(): this(new SystemTimestampProvider()) 
    { } 
} 

這就是說,我們總是尋找在新技術,包括DI框架。如果我們放棄了這項技術以獲得更好的效果,我會讓你知道。