【问题标题】:Why does Unity use a Service Locator?为什么 Unity 使用服务定位器?
【发布时间】:2012-02-25 16:16:53
【问题描述】:

我在几个关于在 asp.net mvc3 中使用 Unity 的教程中看到了这行代码。我的印象是服务定位器是一种反模式,而不是最佳实践。这个服务定位器是不是定义的反模式,还是这行代码/这个实现被认为是不好的做法。

ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(Container));

【问题讨论】:

  • 我也看到这个使用了很多,在 Prism StockTrader RI 中,他们也使用带有 MEF 的 ServiceLocator。我也觉得这是一种反模式,因此在 RI 中看到它感到很惊讶。我确实相信这是与定义的反模式相同的服务定位器模式实现。
  • 您倒退了:在您的示例中,使用服务定位器的不是 Unity,而是您的代码插件通过服务定位器统一到 asp.net mvc3。关于服务定位器模式的争论具有宗教性质。 asp.net mvc 团队必须提供一种使用您最喜欢的 DI 容器的方法,这就是他们实现它的方式。想想替代方案。以下是对该问题的更多见解blog.ploeh.dk/2011/08/25/ServiceLocatorRolesVsMechanics.aspx
  • @zespri - 所以不是所有的 Unity 实现都使用服务定位器?
  • 我只知道一个 Unity 实现。它不使用服务定位器。如果您愿意,您可以将其用作服务定位器(即使 Unity 没有明确支持它),但在这种情况下它确实支持它。
  • @zespri - 我非常想避免使用服务定位器,你知道有哪些针对 asp.net mvc3 的教程,其中显示了没有服务定位器的简单统一设置吗?

标签: asp.net-mvc-3 unity-container service-locator


【解决方案1】:

老问题,但为了他人的利益:

虽然我完全同意“服务位置是一种反模式”的说法,但该规则肯定有例外。

当您使用依赖注入(如 Unity)时,是的,当然不要使用 ServiceLocator 并且只对所有服务类使用构造函数注入。 (也不要将“new”用于 DTO 等值对象以外的任何内容。)

但是,在某些情况下,您根本无法使用构造函数注入,然后访问服务的唯一方法是使用解决方法直接访问您的 Unity 容器,在这种情况下,ServiceLocator 是一个很好的标准实现这一目标的方法。当类不是由您实例化(或者更具体地说,它不是由 Unity 实例化)而是由 .NET 框架实例化时,就是这种情况。

ServiceLocator 可能有用的几个简单示例是从以下位置访问在 Unity 容器中注册的服务:

  1. WCF IEndpointBehavior 或 IClientMessageInspector 的实现
  2. WPF IValueConverter 的实现
  3. 或者您可能甚至不一定想从类中访问“服务”,但您只是想编写可单元测试的代码,但由于某种原因,该类根本无法实例化(或不能实例化)很容易),因为它通常由 .NET Framework 构建,因此您将自定义代码提取到可测试的类中,并使用 ServiceLocator 在不可测试的类中解析它。

请注意,这条线并不理想:

ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(Container));

ServiceLocator.Current 属性将在您每次访问 Current 时执行提供的委托,即每次都会创建一个新的 UnityServiceLocator。相反,您可能想要这样做:

IServiceLocator locator = new UnityServiceLocator(container);
ServiceLocator.SetLocatorProvider(() => locator);

【讨论】:

    【解决方案2】:

    如果您创建一个设计为与容器无关的框架,则服务定位器(尽管它在应用程序中应该是禁止使用的)是一个额外的间接层,允许您将 Unity 换成不同的东西。此外,服务定位器的使用并不强制使用 DI 对使用该框架的应用程序。

    【讨论】:

      【解决方案3】:

      这与人们谈论的反模式相同。该行所做的只是将服务定位器提供程序设置为 UnityServiceLocator 的一个实例,即使用 ISerivceLocator 的 Unity 实现。或者,如果您愿意,您可以拥有自己的实现是 IServiceLocator 并使用它来代替 UnityServiceLocator。

      由于here 列出的各种原因,使用服务定位器被认为是一种不好的做法

      【讨论】:

      • 我同意服务定位器是不好的做法,我只是不确定这是否只是名义上的使用。
      • 如果使用的是IOC容器,如何找到容器?
      • 它有它的位置,请参阅另一个答案,它使您的代码免于直接绑定到特定的 DI 实现。
      • @philsoady 我相信桌面应用程序的答案是将 IUnityContainer 类型的构造函数参数添加到需要容器的任何类(请参阅mvvmandunity.codeplex.com)。对于其他应用程序类型,可能无法做到这一点,因此使用了服务定位器。如果没有其他选择,我个人会说仅使用它来获取 DI 容器是可以接受的。
      猜你喜欢
      • 1970-01-01
      • 2012-09-07
      • 2011-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-25
      • 2020-04-04
      • 2018-06-15
      相关资源
      最近更新 更多