ServiceLocator是反模式吗?
最近我读过Mark Seemann关于Service Locator反模式的文章。
作者指出ServiceLocator为反模式的两个主要原因:
API使用问题(我完全可以使用)
当类使用服务定位器时,很难看到它的依赖关系,因为在大多数情况下,类只有一个PARAMETERLESS构造函数。与ServiceLocator相比,DI方法通过构造函数的参数显式地暴露依赖关系,因此在IntelliSense中很容易看到依赖关系。
维护问题(让我感到困惑)
请考虑以下示例
我们有一个使用服务定位器方法的类'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容器用作服务定位器,则无法实现此目的
有关详细信息,请阅读下面给出的优秀答案。
潇湘沐