7

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

例如我们有:

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

或者

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

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

跟踪代码时会变得更加困难——因为不清楚使用的是什么具体类型——所以我们必须多次检查映射,因为我们试图学习代码的一部分。以上面的例子为例,按下 F12 on:quote.DoSomething()将带您进入界面定义。

实现起来也有点困难——我们需要一个接口 + 具体类 + 配置映射,而替代方案只有 1 个类。

想一想——我不知道有任何东西被“换掉”为另一种类型——所以虽然我们已经实现了 IoC,但我们没有使用它,或者至少——很少使用它。

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

4

5 回答 5

5

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

  1. 所有单元测试都必须使用服务定位器(使用 DI 不涉及DI 容器
  2. 您将整个架构耦合到服务定位器(在DI中,只有Composition Root使用DI Container
  3. 您无法立即看到组件的依赖关系(使用DIConstructor Injection
  4. 您的单元测试变得更加复杂,因为您必须关心您的配置,以免其他测试错误地使用另一个配置(Tear Down)。

http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx

于 2012-07-02T08:02:31.997 回答
4

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

  1. 确定模块边界。
  2. 在同一个模块中,尽可能使用具体的类。
  3. 对于模块间通信,尽可能使用 DI。

模块应该是相对细粒度的。

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

于 2012-07-01T16:21:26.750 回答
2

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

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

于 2012-07-01T16:28:42.720 回答
1

如果您进行单元测试,则某种依赖注入对于存根或模拟...依赖项至关重要。(单元测试不应该遇到依赖,比如文件系统、数据库、网络等)

于 2012-07-01T16:17:11.027 回答
0

我认为您将依赖注入的更一般概念与使用 DI 容器混淆了,这是实现非常灵活的 DI 形式的一种手段。是一篇很好的文章,将 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
    }
}
于 2012-07-01T17:12:24.287 回答