2010-03-26 33 views
23

只是想讓我的頭仍然圍繞着國際奧委會的原則。國際奧委會 - 應使用靜態輔助方法的類與IOC連接?

Q1:靜態方法 - 應該將具有靜態輔助方法的util類與IOC連接起來嗎?

例如,如果我有一個具有多個靜態方法的HttpUtils類,我應該試圖通過IOC將它傳遞給其他業務邏輯類嗎?針對此問題

關注可能是:

Q2:單身 - 什麼之類的東西記錄在那裏你可以通常通過Logger.getInstance訪問它()呼叫類型。您通常會保持原樣,而不是使用IOC將記錄器注入需要它的業務類中?

問題3:靜態類 - 我還沒有真正使用過這個概念,但是如果您正在轉向基於IOC的方法,您通常會如何處理這個問題。

在此先感謝。

回答

30

關於IoC的有趣之處在於,寫入風格的對象通常與這些細節分離。

讓我們使用實用工具類爲例:

public class HttpUtils 
{ 
    public static void DoStuff(int someValue) 
    { 
     // ... 
    } 
} 

在非國際奧委會爲重點的應用程序,你可以直接使用該方法:

public class Foo 
{ 
    public int Value { get; set; } 

    public void DoStuff() 
    { 
     HttpUtils.DoStuff(Value); 
    } 
} 

然而,夫婦的定義DoStuff直接執行。國際奧委會致力於離婚的種種細節,所以不是我們定義自身的操作:

public interface IDoesStuff 
{ 
    void DoStuff(int someValue); 
} 

然後,我們離開房間Foo爲實現改變:

public class Foo 
{ 
    private readonly IDoesStuff _doesStuff; 

    public Foo(IDoesStuff doesStuff) 
    { 
     _doesStuff = doesStuff; 
    } 

    public int Value { get; set; } 

    public void DoStuff() 
    { 
     _doesStuff.DoStuff(Value); 
    } 
} 

這樣可以使FooHttpUtilsDoStuff這個概念的實現者現在是一個配置細節,而不是一個固有的依賴關係(就像靜態方法一樣)。

請注意,Foo不知道它的IDoesStuff是否爲單例。該生存期是也是的配置細節,而不是Foo的固有細節。

總而言之,IoC和static一般都是不一致的,因爲IoC促進變化,根據定義,static可以阻止它。在你的構造函數中聲明你的依賴關係,你會發現你幾乎從來沒有使用過static的功能。

+0

感謝Bryan - 這是否意味着每次都可能會有更多的IOC構造事物(例如記錄器)的開銷?同樣對於utils類型類,我想知道這會不會在重構助手類中的輔助函數時使得重構更難? (我自己使用ReSharper) - 謝謝 – Greg 2010-03-26 21:17:41

+0

大多數IoC容器允許某種範圍的範圍。通過這個,我的意思是說明你的對象是每次(工廠)創建的,每個上下文(工作單元)創建一次,還是每個應用程序(單例)一次。這意味着您可以註冊記錄器,使其僅創建一次。 – 2010-03-26 21:28:05

+2

最終你想消除公用事業類。每個類中的每個方法都與上面的「HttpUtils.DoStuff」方法具有相同的耦合問題。出於這個原因,你不想要求任何*代碼直接依賴於'static'成員。相反,將'HttpUtils.DoStuff'的主體放在'IDoesStuff'後面,並從'HttpUtils'完全刪除該方法。現在,任何可能調用靜態方法的類都可以在其構造函數中接受'IDoesStuff'。維奧拉:不再需要公用事業類! – 2010-03-26 21:37:51

6

IoC容器通常用於注入具有狀態的對象;或者具有多於一個實現的類或接口,即使第二個實現是用於測試目的的模擬。如果這兩個都不是真的,那麼注入它就沒有任何好處。現在最常見的習慣是讓你的課堂接受真實和模擬實現都可以實現的接口。

1)輔助類的靜態方法 - 不,這些通常不會被IoC注入。通常他們是無狀態的公用事業。

要使用一個非常簡單的示例,您不需要名爲StringUtils.Reverse()的實用程序方法的兩個版本。你只需要一個,你可以很容易地編寫測試,因爲它沒有狀態或依賴關係,所以嘲笑它絕對沒有好處。試驗例:

string reversedString = StringUtils.Reverse("input"); 
Assert.AreEqual("tupni", reversedString) 

如果該實用程序是不是真的無狀態(例如取決於HttpContext.Current),那麼你應該做的依賴性明確通過注射它,而不是讓該實用程序的靜態。

2)單身人士:通常是,單身人士注射。但是IoC的一個好處就是你不必擔心是否只有一件東西。您可以通過使用IoC獲得實例靈活性。每次將特定類型作爲單例或新實例的決定都將成爲IoC容器配置的一部分,代碼中的其他任何內容都不需要更改。

因此,單身軀幹停止是一個單獨的問題,必須編入類(以及不必擔心的類有多個問題),它成爲IoC容器的關注點。你不會像「私有構造函數」和方法那樣將類「作爲單例」編碼,你只需將它編碼爲主要關注點,而IoC容器的配置指定它是否是單例,或者某處介於兩者之間,如每個線程一個實例。

3)靜態類 - 靜態方法的自然之家。考慮在適當的地方製作靜態方法擴展方法。你不能注入這些類,因爲你不能創建它們。使用靜態類使程序而不是面向對象的代碼。對於小型輔助方法來說這不是一件壞事,但是如果大部分代碼都是這樣的話,那麼你就不會使用.Net平臺的強大OO功能。

2

按定義靜態方法不需要實例。 DI/IOC的目標是滿足具體類的接口,並且考慮到靜態類和靜態方法根據定義不能實現接口或擴展類,這個問題是沒有意義的。 Theres在傳遞helper類方面毫無意義,因爲不需要實例來使用靜態方法。即使沒有實例,您的代碼也會始終執行相同的靜態幫助程序方法。

在IOC/DI驅動的應用程序中,可以定義接口並且至少有一個實現。它關於管理實例及其依賴關係。

0

當效用類,比如說需要訪問數據庫時,會出現困境。雖然db訪問器需要Ioc,因此實用程序類必須使用Ioc,因此它不能是靜態的。

但我真的希望實用程序類是靜態的,所以很容易被使用。我不想填充每個需要實用類的消費類的構造函數。

消費類本身可能甚至不需要自己的數據庫訪問。所以我不想注入數據庫訪問器並將其傳遞到實用程序類中。

猜猜現在還沒有完美的解決方案。有一天,我希望我們更進一步,除了構造函數/屬性注入,還有「全局上下文注入/配置」或「靜態注入」,將Ioc應用於對象創建之外。

想一想,爲什麼不呢?

+0

這是一個答案,或只是對問題的評論? – 2013-11-05 18:57:24

相關問題