Dependency injection 何时使用属性注入? 我应该什么时候使用属性注入 如果在完全受控的环境中创建实例,我应该默认使用构造函数注入吗 我使用构造函数注入编写容器无关代码,对吗

Dependency injection 何时使用属性注入? 我应该什么时候使用属性注入 如果在完全受控的环境中创建实例,我应该默认使用构造函数注入吗 我使用构造函数注入编写容器无关代码,对吗,dependency-injection,ioc-container,Dependency Injection,Ioc Container,我应该什么时候使用属性注入 如果依赖项确实是可选的,当您有本地默认值,或者当您的对象图包含循环依赖项时,您应该使用属性注入 但是,在编写业务线应用程序时,您的依赖项不应该是可选的:您应该应用 也不应使用本地默认值,即: “与使用者在同一程序集中定义的抽象的默认实现。”[DIPP&p,第4.2.2节] 本地默认值不应在业务线应用程序中使用,因为它会使测试复杂化,隐藏依赖项,并且容易忘记配置依赖项 对象图也不应该具有循环依赖关系。这是应用程序设计中的一个重要步骤 如果在完全受控的环境中创建实例,我应

我应该什么时候使用属性注入

如果依赖项确实是可选的,当您有本地默认值,或者当您的对象图包含循环依赖项时,您应该使用属性注入

但是,在编写业务线应用程序时,您的依赖项不应该是可选的:您应该应用

也不应使用本地默认值,即:

与使用者在同一程序集中定义的抽象的默认实现。”[DIPP&p,第4.2.2节]

本地默认值不应在业务线应用程序中使用,因为它会使测试复杂化,隐藏依赖项,并且容易忘记配置依赖项

对象图也不应该具有循环依赖关系。这是应用程序设计中的一个重要步骤

如果在完全受控的环境中创建实例,我应该默认使用构造函数注入吗

对。构造函数注入是最好的方法。它使得查看类具有哪些依赖关系变得非常容易,使得需要依赖关系成为可能,并防止时间耦合

我使用构造函数注入编写容器无关代码,对吗

这是正确的。构造函数注入允许您延迟决定使用哪个DI库,以及

对于以上的更详细的解释,以及更多,请阅读我和我自己的书(DIPP&p)

属性注入的实用性非常有限,以至于在写这本书时,Mark和我甚至讨论了将属性注入标记为反模式。最后,我们觉得我们无法提出一个强有力的理由,例如,我们决定在那个版本中将其描述为反模式。环境上下文的情况非常清楚,而属性注入则更加混乱。但是,这就是为什么我们在属性注入部分(4.4)中添加了许多警告注释的原因,因为我们强烈地感到,对于大多数情况,属性注入并不是一个好的解决方案

不过,属性注入一开始似乎解决了几个问题,例如(构造函数包含许多依赖项的)问题。然而,构造函数过度注入几乎总是由设计缺陷引起的,例如:

  • 阶级拥有
  • 通过基类而不是or应用

公认的答案支持构造函数注入,并对属性注入采取了相当关键的立场。因此,如果正确使用,它不会将重点放在解决属性注入实际解决的问题上。因此,我想借此机会阐述其中一些观点,并对公认的答案提出一些反驳

我应该什么时候使用属性注入

假设您有一个包含100多个控制器的项目,所有这些控制器都在扩展一个自定义基本控制器(父服务)。在这种情况下,当一个服务由几个子服务扩展时,使用构造函数注入是一个负担:对于您创建的每个构造函数,您都需要将参数传递给父服务的构造函数。如果您决定扩展父服务的构造函数签名,您还将被迫扩展所有子服务构造函数的签名

为了使这个例子更生动,假设您使用一个具有无参数构造函数的基本控制器启动项目

  • 现在,一个月后,您决定在基本控制器中使用记录器服务。→ 您不仅需要更改基本控制器构造函数的签名,还需要更改100多个子控制器的签名
  • 现在,一个月后,您需要访问基本控制器中的用户服务→ 同样,您必须更改100多个子控制器的构造函数签名
  • 你明白了
有了属性注入,您只需向父服务添加必要的属性,并让DI机制通过反射处理注入,就可以很容易地避免这一切不便。作为一个副作用,这也大大降低了合并冲突的风险(因为所接触的文件减少到了最低限度)

到目前为止,我主要讨论的是控制器,但这个示例适用于具有服务层次结构的任何情况——该层次结构越深或越宽,构造函数注入的负担就越大。然而,在项目中完全避免服务层次结构可能并不总是一个合理的选择

可以说,属性和构造函数注入之间的决定实际上是实用主义和OOP“纯粹主义”之间的决定

从“纯粹主义”OOP的角度来看,规则是(如接受答案中所述)通过类的构造函数初始化类的所有必需字段,以避免在“未完成”状态下授予对新创建实例的任何访问权限(这可能会导致稍后抛出异常)

根据这条规则,OOP纯粹主义者有一个正确的观点,即属性注入(暂时)会使您的服务处于“未完成”状态(构造函数返回到属性被注入的时间间隔),这会增加应用程序崩溃的风险

然而,当谈到由IOC/DI容器管理的服务时,如果您认为DI机制负责解决依赖图,并在任何用户操作或API请求真正进入系统或需要处理之前将所有的东西都连接起来,那么这个风险实际上会降低到零。例如