混淆使用IOC容器,服务定位器和工厂

时间:2012-06-29 21:37:10

标签: dependency-injection inversion-of-control ioc-container anti-patterns service-locator

假设我有BaseForm取决于ILoggerIResourceManager或类似的东西。目前,它使用服务定位器解决了所需服务的正确实现,我知道这是一种反模式。

  • 使用构造函数注入正确的方法来解决这种依赖吗?
  • 我是否必须在容器中注册我的BaseForm(及其'派生类型)才能创建具有已解析依赖关系的实例?这不会使一切变得复杂吗?
  • 使用围绕服务定位器的静态工厂是不是很糟糕?
  • 除了单元测试外,由于使用服务定位器反模式,我真的会受到惩罚吗?

很抱歉一次提出很多问题。我已经阅读了以下SO问题和许多其他问题,但阅读它们只会增加我的困惑:

1 个答案:

答案 0 :(得分:8)

如果可能的话,你应该总是选择依赖注入,因为它有一些明确的力量。但是,使用UI技术,并不总是可以使用依赖注入,因为某些UI技术(例如.NET空间,Win Forms和Web窗体)只允许您的UI类(窗体,页面,控件等)具有默认构造函数。在这种情况下,你将不得不回到其他东西,即服务定位器。

在这种情况下,我可以给你以下建议:

  • 只回退到服务定位器,用于使用依赖注入无法通过容器创建的UI类,以及无论如何都不是单元测试的东西。
  • 尝试在这些UI类中实现尽可能少的逻辑(仅Humble objects,只有视图相关的东西)。这允许您尽可能地进行单元测试。
  • 围绕静态方法包装容器,以将容器与应用程序的其余部分隐藏起来。当无法解析依赖关系时,请确保对此静态方法的调用失败。
  • 解析该类型的(默认)构造函数中的所有依赖项。这允许应用程序在创建该类型时无法解析其中一个依赖项时快速失败,而不是稍后单击某个按钮时。
  • 在应用启动期间(或使用单元测试)检查是否可以创建所有这些UI类型。这使您无需通过整个应用程序(通过打开所有表单)来查看DI配置中是否存在错误。
  • 当容器无法构建类型时,没有理由在容器中注册它们。如果它们可以由容器创建(例如使用ASP.NET MVC Controller类),那么显式注册它们会很有用,因为某些容器允许您预先验证配置,这将检测这些类型中的配置错误程。

除了单元测试之外,还有另外两个反对使用服务定位器的重要论据,由Mark Seemann在其着名的博客文章Service Locator is an Anti-Pattern中提供:

  • 服务定位器“隐藏类的依赖关系,导致运行时错误而不是编译时错误”
  • 服务定位器“使代码更难维护”