全球对抗dependency injection

有人说使用dependency injection更好。 这是为什么?

我认为最好是拥有一些全局的,易于访问的类,而不是庞大的构造函数。

它会以任何方式影响应用程序的速度吗?

这两者的混合可能是最好的。

主要优点是解耦 ,这将有助于unit testing。 这种情况完全取决于您如何编写这些“易于访问的类”。

这个想法是这样的。 类通过仅依赖于契约interface )而与实现class )依赖性分离。 在您的实时环境中,您可能永远不会提供新的实现类,但在您的测试环境中,您很可能会(无论是手工制作的存根,还是来自模拟框架的模拟类)。

应用程序的速度需要分析,但是使用DI框架可能会产生一些开销,而不是直接与你知道的单例交谈。 重要的问题是:这是一个问题吗? 只有性能期望和分析可以告诉你。 根据我的经验,其好处远远超过可忽略不计的性能损失。

您可能会使用static类和方法作为Globals。 它们没有任何性能影响。 但是,静态类不适用于可测试性

静态方法的缺点是什么?

此外,一旦您的代码与静态类(Globals)紧密耦合,您将来无法用替代实现替换它们。 因此,除非在非常简单的情况下使用,否则Globals可能不是好的设计。

请注意,静态类和方法是编译时绑定,其中DI是运行时绑定帮助您保持课堂松散耦合

使用“全局”和DI之间存在巨大差异。 首先,路径通常不会被引导,因为您可能会逐步执行单例和服务定位器 。 今天两者都被认为是一种反模式。 原因是我们应该设计可测试代码,当我们需要更改维护代码库或满足新需求时,这给我们带来了很大的好处。 如果代码分离,则易于实现可测试性。 你猜测全局行为对解耦没有帮助,所以例如如果你有代码加入一个静态单例,要测试这样的代码你需要单例本身,你不能嘲笑它,这很糟糕因为你不能随心所欲地强调你的系统。 服务定位器乍一看似乎更好:如果您需要测试,您可以逐步模拟服务定位器,但您必须:

  • 事先知道被测系统将向定位器询问哪些服务
  • 总是创建一个“递归模拟”,因为你可能也会模拟返回的服务。

构造函数中的DI是代码解耦的好方法,因为您非常清楚地说明了对象需要运行的内容,并且您可以一目了然地判断模拟,存根等等。 请注意DI将起作用并帮助您,如果您确保不将DI内核作为代码中的依赖关系:这将在反模式中转换DI(您解耦代码,但是将它绑定到容器),所以记得要学习并真正实现基于模式的根模式 ,这真的会让你更好地编写更好的可测试代码。

我认为关于这个主题的最高职位有一个非常好的DI总结以及如何以正确的方式使用它: dependency injection(DI)“友好”库

如果您想深入了解该主题,我可以推荐Mark Seeman撰写的“.NET中的dependency injection”一书。