2011-08-29 36 views
3

我讀過許多關於在開發中使用IoC容器的有趣文章。在許多情況下,作者建議我們寫自己的簡單的包裝裏面隱藏的接口,像Ninject,Castle.Windsor,統一等在自己的抽象中使用IoC高級功能

包裝的實現看起來像這樣(爲Ninject)讀取容器:

/// <summary> 
/// Contains links for service contract and realization. 
/// </summary> 
public static class IoC 
{ 
    static readonly IKernel kernel; 
    static IoC() 
    { 
     kernel = new StandardKernel(); 
    } 

    public static void RegisterService<T>(Type service) 
    { 
     kernel.Bind<T>().To(service); 
    } 

    public static T Resolve<T>() 
    { 
     return kernel.Get<T>(); 
    } 
} 

好的,但是如何使用這種模式的高級功能?例如,我喜歡使用InRequestScope()或InSingletonScope()等生命週期管理修飾符,並且許多容器都支持相同的修飾符。隨着上述模式,我可以扔掉ninject並使用15-lines implementation。區別在哪裏?

我也看着CommonServiceLocator試圖找到豐富的包裝,但它與我的IoC類沒有太大的區別。 現在我認爲我不應該自己製作自行車並直接使用全功能容器。你呢?

+0

做的人轉而多久容器?這真的很常見嗎?無論如何,你的類不應該依賴於容器,所以替換它應該很容易,抽象與否,不是嗎? –

+3

通常,沒有理由將您的DI容器抽象出來,因爲您應該只在組合根中使用它。其他一切都被稱爲[服務定位器反模式](http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx),應該避免。 –

+1

@R。 Martinho費爾南德斯:我FWIW交換容器中一個相當大的活​​代碼庫最近一個星期,但承認有些事情不是我做的每一個* *星期:) –

回答

6

您的應用程序代碼應完全忽略DI容器的存在,不管是哪一個。相反,需要依賴類應該通過構造器注入要求他們,就像這樣:

public class Foo 
{ 
    private readonly IBar bar; 

    public Foo(IBar bar) 
    { 
     if (bar == null) 
      throw new ArgumentNullException("bar"); 

     this.bar = bar; 
    } 

    public void SomeMethod() 
    { 
     // use this.bar from here... 
    } 
} 

通知警衛條款的組合和readonly關鍵字如何保護類的不變量。從Foo類的任何方法,this.Bar保證可用。

所有DI容器都理解這種設計模式,因此您可以讓您選擇的容器組成來自Composition Root的整個應用程序圖形。從這裏你可以使用全部容器的高級功能,而不用擔心代碼庫的其餘部分會與容器耦合。

+0

所以,根據這個我應該使用**來解析**。所有的綁定代碼(包括IoC depandant作品)都應該滿足根目錄並且可以進行修改。那是對的嗎? –

+0

您不需要用於解析的包裝器,因爲您只需要在組合根中解析:http://blog.ploeh.dk/2010/09/29/TheRegisterResolveReleasePattern.aspx –

0

我不會推薦抽象你的IOC框架。對於95%的應用程序而言,沒有充足的理由需要。

剛剛露出內核是這樣的:

public static class IoC 
{ 
    public IKernel Kernel { get { return _kernel; } } 

    ... etc ... 
} 

如果你絕望抽象掉你的IOC框架的話,我還是會有直接訪問真正的框架,當你需要的某種方式。例如,您可以將抽象內核轉換爲實際的內核。當然,只有當你想要使用抽象不提供的特定功能時,你纔會偶爾做這件事。

有一件事要注意你從NInject發佈的例子 - 我想說這個靜態IOC類的目的是提供對內核單例實例的訪問,而不是將NInject從應用程序中隱藏起來。

+0

我不明白這一點。爲什麼內核不能成爲應用程序啓動方法中的局部變量?爲什麼你需要暴露它?這難道不是故意失去它給你帶來的一些好處嗎? –

+0

在理想的世界裏,是的,不碰內核將會很棒。但是,如果您使用任何基於大型代碼的工作,或者任何類型的傳統平臺(如ASP.NET Web窗體),則不能只依賴於始終進行構造函數注入。您需要能夠執行諸如Kernel.Inject(this),Kernel.Get 等等。您經常需要訪問內核來編寫測試。 – cbp

1

做一些死靈法,但我認爲其他答案錯過了你的觀點 - 部分。 您一直在談論「高級功能」,如範圍界定爲。雖然實際的實現沒有引用容器,但它仍然有些依賴於這些功能。所以我同意,即使容器僅用於組合根,您的實現可能不會是100%的容器不可知論者。如果是這樣,這意味着你正在重新發明輪子(如請求範圍...)

現在,如果你需要的是像SingletonRequest「標準」的範圍界定 - 這是由大量的集裝箱的支持 - 這可能是歡顏使用的抽象(自定義的),這樣你就可以輕鬆更換容器(用於例如,你可能想要對它們進行基準測試......)。

當您開始接觸更高級的功能時,例如自定義範圍Ninject .InCallScope(),.InNamedScope()它越來越有可能交換容器將會工作太多。所以對「抽象」幾乎沒有用處,因爲「抽象」對於容器來說非常特殊。現在

您應該調查「鎖定」到特定的DI容器是否徹底是值得的高級功能的好處。

您使用更加專業的容器的功能,更多的工作,這將是切換容器,可能使其成爲不合算非常快。它限制你未來的選擇。如果沒有更新..你卡住了。如果它對於不斷增長的用戶羣來說太慢了,你就會陷入困境。

你必須要平衡的獨立性,可測試性,可維護性,簡單(...也許更多指標分析)。

我不認爲有人可以給你一個有效的答案是不知道你的具體情況。而且,這方面的經驗往往取決於自己的經驗。當人們開發框架時,人們可能會說「永遠不會」。如果一個人正在開發中等規模的最終用戶應用程序,那麼這是值得的。我個人一直使用命名範圍,調用範圍,自定義範圍,ninject.extensions.Factory(+甚至更強大的自定義版本),截取,上下文保留,上下文操作,條件綁定等高級功能, ... 很多。在整整4年的發展過程中(8位開發人員),沒有人對此表示遺憾。只是說可以爲它感到滿意。但我仍然建議大家對這個決定非常小心。我當然不提倡它。

最後一件事。我所知道的最可怕的項目是一個,它試圖完成所有的事情,多次推遲它的發佈,並以大量花錢結束,而不是一個硬幣收入。創建一個低劣的軟件,賺錢,然後不得不修復很多技術債務是不好的。但與首先不賺一毛錢相比,這是一個奢侈品問題。