是的ServiceLocator一个反模式? [英] Is ServiceLocator an anti-pattern?

查看:143
本文介绍了是的ServiceLocator一个反模式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有关服务定位器反模式最近我读过马克·塞曼的文章

Recently I've read Mark Seemann's article about Service Locator anti-pattern.

作者指出了两个主要的原因是的ServiceLocator反模式:

Author points out two main reasons why ServiceLocator is anti-pattern:


  1. API的使用问题(其中我与完美的罚款)结果
    当类使用了服务定位器这是很难看到它的依赖关系,在大多数情况下,类只有一个参数的构造函数。
    在与服务定位相比之下,DI办法明确通过公开构造函数的参数依赖所以依赖在IntelliSence容易看到。

  1. API usage issue (which I'm perfectly fine with)
    When class employs a Service locator it is very hard to see its dependencies as, in most cases, class has only one PARAMETERLESS constructor. In contrast with ServiceLocator, DI approach explicitly expose dependencies via constructor's parameters so dependencies are easy seen in IntelliSence.

维护问题(这让我为难)结果
考虑下面的expample

Maintenance issue (which puzzles me)
Consider the following expample

我们有一个类的的MyType 的,其采用的服务定位的方式:

We have a class 'MyType' which employs a Service locator approach:

public class MyType
{
    public void MyMethod()
    {
        var dep1 = Locator.Resolve<IDep1>();
        dep1.DoSomething();
    }
}

现在我们要另一个依赖添加到类的MyType的

Now we want to add another dependency to class 'MyType'

public class MyType
{
    public void MyMethod()
    {
        var dep1 = Locator.Resolve<IDep1>();
        dep1.DoSomething();

        // new dependency
        var dep2 = Locator.Resolve<IDep2>();
        dep2.DoSomething();
    }
}

这是我的误解开始。作者说:

And here is my misunderstanding start. Author says:

它成为了很多困难要告诉您是否引入重大更改与否。您需要了解其正在使用的服务定位器整个应用程序,编译器是不会帮你的。

It becomes a lot harder to tell whether you are introducing a breaking change or not. You need to understand the entire application in which the Service Locator is being used, and the compiler is not going to help you.

但是等一下,如果我们使用DI方法中,我们将推出与构造另一个参数(在构造函数注入的情况下)的依赖。而问题将依然存在。如果我们可能会忘记设置服务定位,那么我们可能会忘记在我们的Io​​C容器和DI方法添加一个新的映射也有同样的运行时间的问题。

But wait a second, if we were using DI approach, we would introduce a dependency with another parameter in constructor (in case of constructor injection). And the problem will be still there. If we may forget to setup ServiceLocator, then we may forget to add a new mapping in our IoC container and DI approach would have the same run-time problem.

此外,笔者提到的单元测试的困难。但是,会不会我们与DI方法的问题?不会,我们需要更新它被实例化类中的所有测试?我们将更新他们通过一项新的嘲笑依赖只是为了让我们的测试编译。而且我没有看到从更新和时间花费任何好处。

Also, author mentioned about unit test difficulties. But, won't we have issues with DI approach? Won't we need to update all tests which were instantiating that class? We will updated them to pass a new mocked dependency just to make our test compilable. And I don't see any benefits from that update and time spending.

我并不想捍卫服务定位器的方法。但是,这种误解让我觉得我失去的东西很重要。可能有人打消了我的疑虑?

I'm not trying to defend Service Locator approach. But this misunderstanding make me think that I'm losing something very important. Could somebody dispel my doubts?

更新(摘要):

我的问题答案是服务定位器反模式实际上取决于具体情况。而且我绝对不会建议从您的工具列表,把它划掉。也许当你开始处理遗留code将变得非常方便。如果你幸运地在项目的一开始就那么DI的办法可能是更好的选择,因为它拥有服务定位器一定的优势。

The answer for my question "Is Service Locator anti-pattern" really depends upon the circumstances. And I definitely wouldn't suggest to cross it out from your tool list. It might be become very handy when you start dealing with a legacy code. If you're lucky enough to be at the very beginning of your project then DI approach might be a better choice as it has some advantages over Service Locator.

在此可以说服我不使用服务定位为我的新项目主要区别:

And here is main differences which convinced me to not use Service Locator for my new projects:


  • 最明显,最重要的是:服务定位器隐藏类依赖性

  • 如果您正在使用一些IoC容器它可能会在扫描所有启动构造函数来验证所有的依赖关系,并给你失踪映射(或错误配置)即时反馈;这是不可能的,如果您使用的IoC容器作为服务定位器

有关详细信息,阅读将在下面给出答案优良

For details read excellent answers which are given below.

推荐答案

如果你定义只是因为有一些地方不适合,则是它是一个反模式的情况下作为图案反模式。但与所有的推理模式也将是反模式。

If you define patterns as anti-patterns just because there are some situations where it does not fit, then YES it's an anti pattern. But with that reasoning all patterns would also be anti patterns.

相反,我们要看看是否有模式的有效用途,并为服务定位器有几个用例。但是,让我们通过看你已经给出的例子开始。

Instead we have to look if there are valid usages of the patterns, and for Service Locator there are several use cases. But let's start by looking at the examples that you have given.

public class MyType
{
    public void MyMethod()
    {
        var dep1 = Locator.Resolve<IDep1>();
        dep1.DoSomething();

        // new dependency
        var dep2 = Locator.Resolve<IDep2>();
        dep2.DoSomething();
    }
}

该维护的噩梦与类是依赖被隐藏。如果您创建和使用类:

The maintenance nightmare with that class is that the dependencies are hidden. If you create and use that class:

var myType = new MyType();
myType.MyMethod();

您不明白,它如果他们使用的服务,位置隐蔽具有依赖性。现在,如果我们不是使用依赖注入:

You do not understand that it has dependencies if they are hidden using service location. Now, if we instead use dependency injection:

public class MyType
{
    public MyType(IDep1 dep1, IDep2 dep2)
    {
    }

    public void MyMethod()
    {
        dep1.DoSomething();

        // new dependency
        dep2.DoSomething();
    }
}

您可以直接当场依赖和满足他们之前无法使用的类。

You can directly spot the dependencies and cannot use the classes before satisfying them.

在商业应用的一个典型的线,你应该避免正是由于这个原因使用服务的位置。它应该是当没有其他的选择要使用的模式。

In a typical line of business application you should avoid the use of service location for that very reason. It should be the pattern to use when there are no other options.

没有。

例如,控制容器的反转不会没有服务点工作。这是他们如何解决内部的服务。

For instance, inversion of control containers would not work without service location. It's how they resolve the services internally.

但是,一个更好的例子是ASP.NET MVC和的WebAPI。你认为使依赖注入可能在控制器中?这是正确的 - 服务地点

But a much better example is ASP.NET MVC and WebApi. What do you think makes the dependency injection possible in the controllers? That's right -- service location.

但是等一下,如果我们使用DI的方法,我们会引入
  在构造另一参数(在的情况下,依赖
  构造器注入)。而问题将依然存在。

But wait a second, if we were using DI approach, we would introduce a dependency with another parameter in constructor (in case of constructor injection). And the problem will be still there.

有两个严重的问题:


  1. 随着服务的位置,您还添加其他的依赖:服务定位器。

  2. 你怎么知道的依赖关系应该有生命周期,以及如何/时,他们应该得到清理?

通过构造函数注入使用的容器,你得到免费的。

With constructor injection using a container you get that for free.

如果我们可以
  忘了设置服务定位,那么我们可能会忘记添加新的
  在我们的Io​​C容器和DI方式映射也有同样的
  运行时的问题。

If we may forget to setup ServiceLocator, then we may forget to add a new mapping in our IoC container and DI approach would have the same run-time problem.

这是真的。但构造器注入你不必扫描整个班级找出哪些依赖失踪。

That's true. But with constructor injection you do not have to scan the entire class to figure out which dependencies are missing.

和一些更好的容器也验证所有的依赖在启动时(通过扫描所有构造函数)。因此,与这些容器你得到的运行时错误直接,而不是在以后的某个时间点。

And some better containers also validate all dependencies at startup (by scanning all constructors). So with those containers you get the runtime error directly, and not at some later temporal point.

此外,笔者提到的单元测试的困难。然而不会,我们有办法DI问题?

Also, author mentioned about unit test difficulties. But, won't we have issues with DI approach?

没有。正如你不必依赖于一个静态的服务定位器。你有没有试图让静态的依赖工作的并行测试?这不好玩。

No. As you do not have a dependency to a static service locator. Have you tried to get parallel tests working with static dependencies? It's not fun.

这篇关于是的ServiceLocator一个反模式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆