已经发布了几个问题,其中包含有关依赖项注入的特定问题,例如什么时候使用它以及支持它的框架。 然而, 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(); ... } }