7

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

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

3 回答 3

13

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

虽然我绝对同意“服务位置是一种反模式”的口头禅,但该规则肯定有例外。

当您使用依赖注入(如 Unity)时,是的,当然不要使用 ServiceLocator 并且只对所有服务类使用构造函数注入。(除了像 DTO 这样的值对象之外,不要将“new”用于任何东西。)

但是,在某些情况下,您根本无法使用构造函数注入,然后访问服务的唯一方法是使用解决方法直接访问您的 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);
于 2013-08-23T16:52:22.070 回答
7

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

于 2012-02-03T06:49:03.043 回答
2

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

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

于 2012-02-03T00:27:33.733 回答