已經發布了幾個問題,其中包含有關依賴項注入的特定問題,例如什麼時候使用它以及支持它的框架。 然而, html
什麼是依賴項注入?什麼時候/爲何/不該該使用它? 程序員
假設您想去釣魚: 網絡
若是沒有依賴項注入,則您須要本身作好一切。 您須要找到一條船,購買一根釣魚竿,尋找誘餌等。固然有可能,可是這給您帶來了不少責任。 用軟件術語,這意味着您必須對全部這些內容執行查找。 框架
使用依賴注入,其餘人能夠完成全部準備工做,併爲您提供所需的設備。 您將收到(「被注射」)船,釣魚竿和誘餌-隨時可用。 ssh
依賴注入將依賴傳遞給其餘對象或框架 (依賴注入器)。 ide
依賴注入使測試更加容易。 注入能夠經過構造函數完成。 函數
SomeClass()
的構造函數以下: 單元測試
public SomeClass() { myObject = Factory.getObject(); }
問題 :若是myObject
涉及諸如磁盤訪問或網絡訪問之類的複雜任務,則很難在SomeClass()
上進行單元測試。 程序員必須模擬myObject
並可能攔截工廠調用。 測試
替代解決方案 : this
myObject
做爲參數傳遞給構造函數 public SomeClass (MyClass myObject) { this.myObject = myObject; }
myObject
能夠直接傳遞,這使測試更加容易。
沒有依賴注入的狀況下,很難在單元測試中隔離組件。
2013年,當我撰寫此答案時,這是Google Testing Blog的一個主要主題。 這對我來講仍然是最大的優點,由於程序員在運行時設計中並不老是須要額外的靈活性(例如,對於服務定位器或相似的模式)。 程序員常常須要在測試期間隔離類。
依賴注入是一種實踐,其中設計對象的方式是使它們從其餘代碼段接收對象的實例,而不是在內部構造它們。 這意味着能夠在不更改代碼的狀況下替換任何實現該對象所需接口的對象,從而簡化了測試並改善了去耦。
例如,考慮如下狀況:
public class PersonService { public void addManager( Person employee, Person newManager ) { ... } public void removeManager( Person employee, Person oldManager ) { ... } public Group getGroupByManager( Person manager ) { ... } } public class GroupMembershipService() { public void addPersonToGroup( Person person, Group group ) { ... } public void removePersonFromGroup( Person person, Group group ) { ... } }
在這個例子中,實施PersonService::addManager
和PersonService::removeManager
將須要的實例GroupMembershipService
,以完成其工做。 若是沒有依賴注入,這樣作的傳統方式是實例化一個新GroupMembershipService
中的構造PersonService
和使用實例屬性中的兩種功能。 可是,若是GroupMembershipService
的構造函數有不少要求,或者更糟糕的是,則須要在GroupMembershipService
上調用一些初始化「 setter」,代碼會快速增加,而且PersonService
如今不只依賴於GroupMembershipService
並且取決於還有GroupMembershipService
依賴的其餘全部內容。 此外,與GroupMembershipService
的連接被硬編碼到PersonService
,這意味着您不能「 GroupMembershipService
」 GroupMembershipService
進行測試,也不能在應用程序的不一樣部分中使用策略模式。
依賴注入,而不是實例化GroupMembershipService
你的內PersonService
,你要麼把它傳遞到PersonService
構造,不然添加屬性(getter和setter)來設置它的本地實例。 這意味着您的PersonService
再也不須要擔憂如何建立GroupMembershipService
,而只需接受它所提供的服務並與之一塊兒使用。 這也意味着能夠將任何屬於GroupMembershipService
的子類或實現GroupMembershipService
接口的東西「注入」到PersonService
,而PersonService
不須要知道更改。
到目前爲止,我發現的最佳定義是James Shore定義的 :
「依賴注入」是5美分概念的25美圓術語。 依賴注入意味着給對象一個實例變量。 [...]。
Martin Fowler的一篇文章可能也頗有用。
依賴注入基本上是提供對象須要的對象(其依賴),而不是讓對象本身構造它們。 這是一種很是有用的測試技術,由於它容許對依賴項進行模擬或存根。
能夠經過多種方式將依賴項注入到對象中(例如構造函數注入或setter注入)。 甚至可使用專門的依賴項注入框架(例如Spring)來作到這一點,可是確定不是必需的。 您不須要那些框架具備依賴項注入。 顯式實例化和傳遞對象(依賴項)與框架注入同樣好。
「依賴注入」不只僅意味着使用參數化的構造函數和公共設置器嗎?
沒有依賴項注入的構造函數:
public class Example { private DatabaseThingie myDatabase; public Example() { myDatabase = new DatabaseThingie(); } public void doStuff() { ... myDatabase.getData(); ... } }
具備依賴項注入的構造函數:
public class Example { private DatabaseThingie myDatabase; public Example(DatabaseThingie useThisDatabaseInstead) { myDatabase = useThisDatabaseInstead; } public void doStuff() { ... myDatabase.getData(); ... } }