描述
在软件工程中
,依赖注入是一种技术,一个对象(或静态方法)提供另一个对象的依赖关系。依赖项是可以使用的对象(服务
)。注入是将依赖项传递给将使用它的依赖对象(客户端
)。该服务是客户状态的一部分
。将服务传递给客户端,而不是允许客户端构建或查找服务
,这是该模式的基本要求。
这个基本要求意味着使用新的
或静态方法
在类中产生的值(服务
)是被禁止的。客户应接受从外部传入的值。这可以让客户获得依赖别人的问题。
依赖注入背后的意图是将
对象分离
到不需要更改客户端代码的程度,因为它所依赖的对象需要更改为不同的对象。
依赖注入是更广泛的控制反转
技术的一种形式。与其他形式的控制反转一样,依赖注入支持依赖反转原理
。客户端将提供依赖关系的责任委托给外部代码(注入器
)。客户端不允许调用注入器代码。注入代码构造服务并调用客户端来注入它们。这意味着客户端代码不需要知道注入代码。客户不需要知道如何构建服务。客户端不需要知道它使用的是哪个实际的服务。客户端只需要知道服务的内在接口,因为它们定义了客户端如何使用服务。这将使用和施工的责任分开。
对于客户端来说,接受依赖注入有三种常见方式:setter
,interface
和constructor
基注入。安装人员和施工人员注射的区别主要在于何时可以使用。接口注入的不同之处在于依赖关系有机会控制自己的注入。每个要求单独的构建代码(注入器
)负责将客户端及其依赖关系引入彼此。
作用
依赖注入设计模式
解决了如下问题:
- 应用程序如何独立于其对象的创建方式?
- 一个类如何独立于它创建的对象的方式?
- 如何在单独的配置文件中指定创建对象的方式?
- 应用程序如何支持不同的配置?
直接在需要对象的类中创建对象是不灵活的,因为它将类提交给特定的对象,并且无法在以后独立于(不必更改)类来更改实例化。如果需要其他对象,它会阻止该类可重用,并且使类难以测试,因为实际对象不能用模拟对象替换。
依赖注入设计模式描述了如何解决这些问题:
- 定义一个独立的(注入器)对象,创建并注入一个类需要的对象。
- 一个类从注入器对象接受它需要的对象,而不是直接创建对象。
这使得一个类独立于其对象的创建方式(具体的类被实例化)。
一个类不再负责创建它需要的对象,并且它不必像Abstract Factory
设计模式那样将实例化委派给一个工厂对象。
这极大地简化了一个类,使其更易于实现,更改,测试和重用。
优点
- 依赖注入使客户可以灵活配置。只有客户的行为是固定的。客户可能会采取任何支持客户期望的内在接口的行为。
- 依赖注入可用于将系统的配置细节外部化到配置文件中,从而允许在不重新编译的情况下重新配置系统。可以针对需要不同组件实现的不同情况编写单独的配置。这包括但不限于测试。
- 由于依赖注入不需要对代码行为进行任何更改,因此它可以作为
重构
应用于遗留代码。其结果是客户端是多个独立的和更易于单元测试
使用在隔离存根
或模拟对象
来模拟未测试其他对象。这种易于测试通常是使用依赖注入时首先要注意的好处。 - 依赖注入允许客户端删除需要使用的具体实现的所有知识。这有助于将客户与设计更改和缺陷的影响隔离开来。它提高了可重用性,可测试性和可维护性。
- 减少应用程序对象中的
样板代码
,因为所有用于初始化或设置依赖项的工作都由提供程序组件处理。 - 依赖注入允许并发或独立开发。两个开发人员可以独立开发相互使用的
类
,而只需要知道类将通过的接口。插件
通常由第三方商店开发,它们甚至从来没有与创建使用插件的产品的开发人员交谈。 - 依赖注入减少了类与其依赖之间的耦合。
缺点
- 依赖注入创建客户端,需要通过构造代码提供配置细节。当明显的默认值可用时,这可能是繁重的。
- 依赖注入可以使代码难以追踪(读取),因为它将行为从构造中分离出来。这意味着开发人员必须参考更多文件来了解系统的运行情况。
- 依赖注入通常需要更多的前期开发工作,因为无论何时何地需要它,都不能召唤正确的东西,但必须要求注入它并确保注入。
- 依赖注入迫使复杂性转移到类之外,并进入类之间的联系,这可能并不总是理想或容易管理的。
- 具有讽刺意味的是,依赖注入可以鼓励依赖注入框架。