2012-12-19 26 views
5

也許我錯過了它的文檔,但我想知道我應該如何處理「幫助對象」?我應該注入執行算法所需的對象嗎?我應該注入一切嗎?

代碼示例:

public Path dijkstra(Node startNode, Node endNode) { 
    Set<Node> nodesToInspect = new HashSet<Node>(); // should this Object be injected? 
    Path path = new Path(); // and this one? 

    while (!nodesToInspect.isEmpty()) { 
     // some logic like: 
     path.add(currentNode); 

    } 

    return path; 
} 

我應該注入的一切,或者我應該在某個時候,該算法「知道」說最需要什麼? 我應該嘗試消除每一個「新」?或者是一些對象的創作精品,例如API類一樣的HashSet,ArrayList中,等

+0

http://stackoverflow.com/questions/1005473/must-dependency-injection-come-at-the-expense-封裝 – sdasdadas

回答

2

在您更換一個簡單的new依賴注入,你需要問自己「爲什麼我這樣做呢?」 ......「真的有什麼好處?」。如果答案是「我不知道」或「沒有」,那麼你就不應該這樣做。

在這種情況下,在示例代碼的第一種情況下,我看不出真正的好處。除了該方法之外,不需要知道內部集合是如何表示的......甚至不需要知道它的存在。

你應該問的另一個問題是,是否有一個更簡單,更明顯的實現目標的方式。例如,對path變量使用DI的(最有可能的)目的是允許應用程序使用不同的Path類。但簡單的做法是將Path實例作爲顯式參數傳遞給dijkstra方法。你甚至可以使用超載來使這更可口;例如

public Path dijkstra(Node startNode, Node endNode) { 
    return dijkstra(startNode, endNode, new Path()); 
} 

public Path dijkstra(Node startNode, Node endNode, Path path) { 
    ... 
} 

要考慮的最後一件事是,DI(在Java中)包括反射在一定程度上,是比使用new或工廠對象/方法的經典方法必然更加昂貴。如果您不需要DI的額外靈活性,您不應該爲此付費。


我剛剛注意到,你指的兩個變量是局部變量。我不知道有任何DI框架允許您注入局部變量...

+0

Google Guice可以讓我將某個Provider Object傳遞給我的課程,我可以用它來生成Se很容易。不過我不確定這是否是一種好方法。 –

+0

@ Absurd-Mind - 傳遞提供者的不是傳統的DI(一個'Provider'實際上是一個工廠對象)。此外,你需要問自己你實際達到了什麼(有價值的)。 –

1

請記住設計原則:「封裝經常變化的內容」或「封裝變化的內容」。作爲工程師,你最清楚可能發生什麼變化。您不希望將2012年硬編碼爲直到下一個十年的代碼,但您也不希望將「Math.PI」設置爲配置設置 - 這是額外的開銷和配置你永遠不需要碰觸。

該原則不隨着依賴注入而改變。

您是否正在編寫一個算法,並且知道您需要哪個Set的實現,就像在您的Dijkstra示例中一樣? 自己創建你的對象。但是,如果您的同事即將爲您的用例提供一套完美集成的優化實現,或者如果您正在嘗試使用不同的集合實現進行基準測試,該怎麼辦? 也許你會想要注入一個提供商,直到塵埃落定。收集的可能性較小,但對於您可能認爲是「輔助對象」的類似一次性對象而言,可能性更大。

假設您在不同類型的CreditCardAuthService之間進行選擇,這些類型在運行時可能會有所不同。 偉大的情況下注射。但是如果你簽了一份爲期五年的合同,並且你知道你的代碼會在很久之前被替換? 也許硬編碼到一個服務更有意義。但是,你必須編寫一些單元測試或集成測試,你真的不想使用真正的信用卡後端。 返回依賴注入。

記住:代碼是可塑的。有一天,你可能會認爲你需要翻譯硬編碼的HashSet,並用其他的替換它,這很好。或者,也許你會發現你需要你的服務經常變化,以至於它應該是由Guice控制的,然後你添加一個構造函數參數和一個綁定,並在一天中調用它。不要擔心太多。請記住,僅僅因爲你有一把錘子,並不是每一個問題都是Provider<WoodFasteningService>

0

在使用DI時,我寧願儘可能避免使用「新」。你在容器外創建的每個實例(例如guice注入器)都不能重構爲使用注入(如果你的「Path」實例應該得到一個由配置注入的String「root」,並且你不能在這些對象上使用攔截器。 因此,除非它是一個純粹的實體Pojo,否則我一直使用提供/注入 它也是控制(好萊塢)模式和可測試性倒置的一部分......如果您需要模擬Path或Set in Junit,該怎麼辦?如果你有他們注入(在這種情況下提供商),您可以輕鬆切換具體實施後

+0

好點,但這種方法導致「構造污染」。已經在這種簡單的情況下,我的構造函數將需要兩個提供者,我甚至沒有將完整的算法或依賴項發佈到其他類。此外,用戶應該如何確定哪個Set對於算法是正確的/最好的? –

+0

如果使用構造函數注入,實例也將由g​​uice創建,所以用戶不決定使用哪個實現。但在這種情況下,我更喜歡野外注射。 –

+0

字段注入迫使我在測試時使用依賴注入,這是我不想和/或不能使用的。是的,實例是由提供者創建的,但用戶仍然必須選擇(或有可能更改)正確/最佳提供者。 –

相關問題