何时使用 container.get 与构造函数 @inject?

When to use container.get vs constructor @inject?

我是使用 InversifyJS 的新手,我看到很多 class 的基本示例以及使用 @inject 作为依赖项的构造函数。像这样...

export class Service {
  protected depA: DependencyA;
  protected depB: DependencyB;

  constructor(
    @inject(DependencyA) dependencyA: DependencyA,
    @inject(DependencyB) dependencyB: DependencyB
  ) {
    this.depA = dependencyA;
    this.depB = dependencyB;
  }
}

那些注入的依赖项有 0 个进一步的依赖项。 但是,我有一些同事不使用它,而是使用类似... private readonly service = container.get<Interface>(TYPES.InterfaceSymbol); 调用任何必要的依赖服务。

对于这种示例案例,我想更好地了解何时使用一个而不是另一个。将其写为嵌套列表,其中进一步缩进的列表项是其依赖项。

加上一个替代 console.log() 的 LoggerService,应该可以注入到任何服务中。

在这种情况下,我什么时候应该使用带@inject params 的构造函数而不是container.get()(或者其他一些你知道我不知道的方式)?

对于大多数用例,您应该依赖使用 @inject 的自动依赖注入,而不是使用 container.get 手动查询容器。任何依赖注入框架的要点是,您只需编写 类 及其依赖项,让框架为您处理所有连接,而无需编写样板代码。您不需要手动查询容器,除非您处于框架无法确定依赖关系图的特殊情况。

补充一下 Martin 的回答,DI 也与生命周期有关。 Rest API 中的某些 classes 自然是请求范围的,而其他 classes 是自然的单例,例如中间件 classes。

如果单例 class 想要为当前 HTTP 请求获取一个实例,通常使用 container.get。不过,只要有可能,更喜欢普通的构造函数注入。

示例API

如果它能为您提供解决方案的想法,这里有一些代码片段来自我的 Node.js API,专注于非功能性行为:

DI 组合

当 API 启动时,它会注册依赖项,这里有一些技巧。对于每种类型,您都应该考虑生命周期。一般来说,单例意味着请求 A 可能会干扰请求 B 的风险更大。

一些对象,例如 ClaimsPrincipalLogEntry 自然是请求范围的。

DI 分辨率

我的 API 使用 Inversify Express Utils,它为每个请求创建一个子容器,这也是一种常见的模式,例如 .NET 使用它。

用于管理横切关注点的 class 使用 container.get,尽管这是例外而不是规则:

所有其他 类

DI 管道的要点是处理管道,然后启用简单代码。所以大多数 classes 看起来像这样,很容易推理,也很好测试: