依赖注入

软件工程中,依赖注入(dependency injection,缩写为 DI)是一种软件设计模式,也是实现控制反转的其中一种技术。這种模式能让一个物件接收它所依赖的其他物件。“依赖”是指接收方所需的对象。“注入”是指将“依赖”传递给接收方的过程。在“注入”之后,接收方才会调用该“依赖”[1]。此模式确保了任何想要使用给定服务的物件不需要知道如何建立這些服务。取而代之的是,连接收方物件(像是 client)也不知道它存在的外部代码(注入器)提供接收方所需的服务。

注:编程语言层次下,“接收方”为对象和 class,“依赖”为变量。在提供服务的角度下,“接收方”为客户端,“依赖”为服务。

该设计的目的是为了分离关注点,分离接收方和依赖,从而提供松耦合以及代码重用性

传统编程方式,客户对象自己创建一个服务实例并使用它。这带来的缺点和问题是:

  • 如果使用不同类型的服务对象,就需要修改、重新编译客户类。
  • 客户类需要通过配置来适配服务类及服务类的依赖。如果程序有多个类都使用同一个服务类,这些配置就会变得复杂并分散在程序各处。
  • 难以单元测试。本来需要使用服务类的 mock 或 stub,在这种方式下不太可行。

依赖注入可以解决上述问题:

  • 使用接口或抽象基类,来抽象化依赖实现。
  • 依赖在一个服务容器中注册。客户类构造函数被注入服务实例。框架负责创建依赖实例并在没有使用者时销毁它。

概念

依赖注入涉及四个概念:

  • 服务:任何类,提供了有用功能。
  • 客户:使用服务的类。
  • 接口:客户不应该知道服务实现的细节,只需要知道服务的名稱和 API。
  • 注入器:Injector,也称 assembler、container、provider 或 factory。负责把服务引入给客户。

依赖注入把对象构建与对象注入分开。因此创建对象的 new 关键字也可消失了。

实现方式

  • 建构子注入:依赖由客户对象的构造函数传入。
  • Setter 注入:客户对象暴露一个能接收依赖的 setter 方法。
  • 接口注入:依赖的接口提供一个注入器方法,该方法会把依赖注入到任意一个传给它的客户。客户实现一个setter接口,可设置依赖。

參考資料

  1. ^ James Shore: Dependency Injection Demystified. www.jamesshore.com. [2020-02-06]. (原始内容存档于2020-06-30).