ServiceLocator是反模式吗?

ServiceLocator是反模式吗?

最近我读过Mark Seemann关于Service Locator反模式的文章

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

  1. API使用问题(我完全可以使用)
    当类使用服务定位器时,很难看到它的依赖关系,因为在大多数情况下,类只有一个PARAMETERLESS构造函数。与ServiceLocator相比,DI方法通过构造函数的参数显式地暴露依赖关系,因此在IntelliSense中很容易看到依赖关系。

  2. 维护问题(让我感到困惑)
    请考虑以下示例

我们有一个使用服务定位器方法的类'MyType'

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

现在我们要为类'MyType'添加另一个依赖项

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

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

要判断你是否引入了一个重大改变,要变得更加困难。您需要了解使用Service Locator的整个应用程序,编译器不会帮助您。

但是等一下,如果我们使用DI方法,我们将在构造函数中引入与另一个参数的依赖关系(在构造函数注入的情况下)。问题仍然存在。如果我们忘记设置ServiceLocator,那么我们可能忘记在IoC容器中添加新的映射,并且DI方法将具有相同的运行时问题。

此外,作者还提到了单元测试的难点。但是,我们不会有DI方法的问题吗?我们不需要更新所有实例化该类的测试吗?我们将更新它们以传递一个新的模拟依赖项,以使我们的测试可编译。我没有看到更新和时间花费带来任何好处。

我不是想捍卫Service Locator方法。但这种误解让我觉得我失去了一些非常重要的东西。有人可以消除我的怀疑吗?

更新(摘要):

我的问题“服务定位器是反模式”的答案实际上取决于具体情况。我绝对不会建议你从工具列表中删除它。当您开始处理遗留代码时,它可能会变得非常方便。如果你很幸运能够处于项目的最初阶段,那么DI方法可能是更好的选择,因为它比Service Locator有一些优势。

以下是主要的不同之处,这些差异使我不相信我的新项目使用Service Locator:

  • 最明显和最重要的是:Service Locator隐藏了类依赖项

  • 如果您正在使用某个IoC容器,它可能会在启动时扫描所有构造函数以验证所有依赖项,并为您提供有关丢失映射(或错误配置)的即时反馈; 如果您将IoC容器用作服务定位器,则无法实现此目的

有关详细信息,请阅读下面给出的优秀答案。


白猪掌柜的
浏览 820回答 3
3回答

潇湘沐

我还想指出,如果你重构遗留代码,服务定位器模式不仅不是反模式,而且它也是一种实际需要。没有人会在数百万行代码上挥动魔杖,突然所有的代码都准备就绪了。因此,如果您想开始将DI引入现有代码库,通常情况下您会将内容更改为DI服务,并且引用这些服务的代码通常不会是DI服务。因此,这些服务将需要使用服务定位器,以获取已转换为使用DI的那些服务的实例。因此,当重构大型遗留应用程序以开始使用DI概念时,我会说服务定位器不仅不是反模式,而且它是将DI概念逐渐应用于代码库的唯一方法。
打开App,查看更多内容
随时随地看视频慕课网APP