服务定位器 - 值得吗?

时间:2012-07-01 16:14:47

标签: .net design-patterns service-locator

我们有一个大型解决方案(> 100个项目),几乎每种类型都使用服务定位器(示例1)或我们自己的类型字典(示例2)进行实例化。

例如我们有:

IQuote quote = Registry.Resolve<IQuote>(); 

IQuote quote = Registry.Find<IQuote>(args);

第二个示例转到配置文件,找到使用反射实例化的具体对象。

通过代码跟踪时会让生活变得更加困难 - 因为不清楚使用的是什么具体类型 - 因此我们必须多次检查映射,因为我们正在尝试学习代码的一部分。使用以上作为示例按F12:quote.DoSomething()将转到界面定义。

实现起来也有点困难 - 我们需要一个接口+具体的类+配置映射,当替代只有一个类时。

来想一想 - 我不知道有什么东西曾被“换掉”换成另一种类型 - 所以尽管我们已经实现了IoC,但我们还没有使用过它,或者至少没有用过它。

所以 - 它真的值得吗?我们是否错误/太多地实施了它?我误解了什么吗?

5 个答案:

答案 0 :(得分:4)

在我看来,你不需要考虑到DI,每个班级都要工作。我会使用以下策略:

  1. 确定模块边界。
  2. 在同一模块中,尽可能使用具体类。
  3. 对于模块间通信,请尽可能使用DI。
  4. 模块应该是相对细粒度的。

    在一些常见的地方你需要使用DI,通常它是可替换的数据源和(不经常)算法。使用常识来检查某些东西是否需要更换。如果你发现某些东西需要DI或者受到影响,请不要犹豫,尽早进行重构。

答案 1 :(得分:4)

你们正在使用的是服务定位器,它被视为反模式, 因为:

  1. 所有单元测试必须使用服务定位器(DI不包含 DI容器
  2. 您将整个架构与服务定位器相结合(在 DI 中只有Composition Root正在使用 DI容器
  3. 您无法立即看到组件的依赖关系( DI 构造函数注入
  4. 您的单元测试变得更加复杂,因为您必须关心您的配置,以便其他测试不会错误地使用其他配置(Tear Down)。
  5. http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx

答案 2 :(得分:2)

你展示的不是依赖注入,它是一个可配置的注册表(它也是一种模式,但却完全不同)。所以,是的,看起来是一个坏主意和一种误解。

为了能够从某些设计模式中获益,您必须先了解其中的好处。如果你不了解它们,那么你可能不应该打扰。

答案 3 :(得分:1)

如果你进行单元测试,某种类型的依赖注入对于存根或模拟依赖性是必不可少的。 (单元测试不应该依赖于文件系统,数据库,网络等依赖项。)

答案 4 :(得分:0)

我认为你使用DI容器混淆了更一般的依赖注入概念,这是实现非常灵活的DI形式的一种手段。 Here是一篇很好的文章,将DI解释为一个概念。

在你的场景中,在我看来你可以摆脱DI容器,但是如果只是为了可测试性,可能仍然想要保留某种形式的DI(正如其他人已经指出的那样)。一种常见的实现模式是实现“广泛”构造函数,通过这些构造函数可以注入依赖 ,并在单元测试中使用。此外,还将有“更窄”的构造函数,它将实例化具体类并将它们传递给“宽泛”构造函数。这些可以在生产代码中使用,直到需要实际交换依赖关系。

实施例

class MyClass
{   
    // This will be called from production code
    public MyClass() : this(new Foo(), new Bar())
    {}        

    // This will be called from tests and can be used in production code if needed
    public MyClass(IFoo foo, IBar bar)
    {
       //do whatever you want to do in the ctor here
    }
}