如果可能的话,你应该总是使用依赖注入,因为它有一些明显的优势。然而,对于 UI 技术,并不总是可以使用依赖注入,因为某些 UI 技术(例如,在 .NET 空间中,Win Forms 和 Web Forms)只允许您的 UI 类(表单、页面、控件等)具有默认构造函数。在这种情况下,您将不得不退回到其他东西,即服务定位器。
在这种情况下,我可以给你以下建议:
- 仅针对无法由容器使用依赖注入创建的 UI 类以及无论如何都不是单元测试的东西回退到服务定位器。
- 尝试在这些 UI 类中实现尽可能少的逻辑(作为仅具有视图相关内容的Humble 对象)。这允许您尽可能多地进行单元测试。
- 将容器包裹在一个静态方法周围,以对应用程序的其余部分隐藏容器。确保在无法解决依赖关系时调用此静态方法失败。
- 解析该类型的(默认)构造函数中的所有依赖项。这允许应用程序在创建该类型时无法解决其依赖项之一时快速失败,而不是稍后单击某个按钮时。
- 在应用程序启动期间(或使用单元测试)检查是否可以创建所有这些 UI 类型。这使您不必通过整个应用程序(通过打开所有表单)来查看 DI 配置中是否存在错误。
- 当容器无法构建类型时,没有理由在容器中注册它们。如果它们可以由容器创建(例如使用 ASP.NET MVC 控制器类),则显式注册它们会很有用,因为某些容器允许您预先验证配置,这将正确检测这些类型中的配置错误离开。
除了单元测试之外,还有另外两个反对使用服务定位器的重要论据,这由 Mark Seemann 在他著名的博客文章服务定位器是一种反模式中给出:
- 服务定位器“隐藏类的依赖关系,导致运行时错误而不是编译时错误”
- 服务定位器正在“使代码更难维护”