依赖注入 - 试图避免使用服务定位器

时间:2017-10-18 08:57:17

标签: dependency-injection

遵循我读到的指南: https://www.devtrends.co.uk/blog/how-not-to-do-dependency-injection-the-static-or-singleton-container

我想尝试避免使用服务定位器。 但另一方面,我没有在startup.cs文件中注册所有类型。我不认为在主startup.cs

中引用所有这些内部类型是正确的

我目前有一个工厂类,它有一组构建器类。 每个构建器类都负责创建特定对象。 我不想提前创建所有这些构建器类,因为我可能不需要使用它们并且创建它们有点沉重。 我在上面的链接中看到了如何实现这一点的示例。但是,startup.cs类需要知道所有这些构建器。我不认为这是合适的,我宁愿让工厂阶级成为唯一接触它们的人。我试图理解是否有某种func / action方法可以从startup.cs文件注入我的工厂类。这个func / action将负责创建/注册构建器,然后我可以在类工厂中激活这个func / action。我希望这个func / action接收构建器的接口/类/可能名称但是使用泛型不起作用。我搜索了很多,没有找到任何解决方案所以我认为这是不可能的。 似乎我有2个选择: 1.使用服务定位器。这样只有工厂类才会知道构建者。但是,如果将来,如果我想更改DI,我需要“触摸”工厂类(我污染了工厂类)。希望所有DI代码仅位于startup.cs类中。 2.在startup.cs中注册构建器,但现在startup.cs知道构建器。这种联系代码,而不是单一的责任角色

从startup.cs向工厂类注入一个func / action本来很棒,它会进行注册,但工厂类本身会激活它。 这可能吗?

1 个答案:

答案 0 :(得分:2)

  

我想尝试避免使用服务定位器

很好,因为服务定位器is an anti-patttern

  

不要在startup.cs文件中注册所有类型。

您应该在一个单一的区域进行注册。您的应用程序:启动路径。此区域通常称为Composition Root(构成对象图的位置)。

  

我认为在主startup.cs中引用所有这些内部类型是正确的

无论您如何设计它,启动程序集都是系统中最易变的部分,始终依赖于应用程序中的所有其他程序集。直接或传递(通过另一个引用的程序集)。依赖注入的整个想法是最小化组件之间的耦合,并且这样做的方法是通过将耦合移动到组合根来集中耦合。但是,通过使类型为内部,您可以分散对象组合并限制您的灵活性。例如,为那些注册类型应用装饰器或拦截器并在全局范围内控制它们变得更加困难。请阅读this question and its two top voted answers以获取更多信息。

  

我没有注册所有类型

组合根太大的问题不是一个有效的问题。可以轻松地将Composition Root拆分为多个较小的函数或类,这些函数或类都位于启动程序集中。最重要的是,如果你阅读this,你就会明白明确注册所有类型(a.k.a。"显式注册")通常是没有意义的。在这种情况下,你可能最好不使用没有容器的DI(a.k.a。Pure DI)。明确注册所有类型的组合根不是很容易维护的。 DI Container变得强大的一个领域是通过其批量注册工具。他们使用反射在几行代码中加载和注册一组完整的类型。添加新类型不会导致您的Composition Root发生变化,从而为您提供最高的可维护性。

  

我不想提前创建所有这些构建器类,因为我可能不需要使用它们并且创建它们有点沉重

创建实例永远不会很重。您的injection constructors should be simple和撰写对象图should be reliable。这使得构建即使是最大的对象图也非常快。工厂应减少到an absolute minimum

TLDR;

  • 仅在Composition Root中注册或撰写对象图。
  • 避免使用服务定位器反模式;整个应用程序可以(并且应该)纯粹使用Constructor Injection构建。
  • 使注入构造函数变得简单,并防止它们执行除存储其传入依赖项之外的任何其他操作。
  • 在大多数情况下,不要使用工厂来构建服务。