我试图在工作中引入依赖注入(DI)模式,我们的一位主要开发人员想知道:如果有的话,使用依赖注入模式的缺点是什么?

注意,如果可能的话,我在这里寻找一个详尽的列表,而不是关于这个主题的主观讨论。


澄清:我谈论的是依赖注入模式(参见Martin Fowler的这篇文章),而不是特定的框架,无论是基于xml的(如Spring)还是基于代码的(如Guice),还是“自滚动”的框架。


Reddit的subreddit /r/programming上正在进行一些深入的讨论/咆哮/辩论。


当前回答

没有任何DI的代码会面临众所周知的陷入意大利面条代码的风险——一些症状是类和方法太大,做太多,不容易更改、分解、重构或测试。

大量使用DI的代码可以是Ravioli代码,其中每个小类就像一个单独的Ravioli块——它只做一件小事,并且遵循单一责任原则,这是很好的。但是从类本身来看,很难看到系统作为一个整体在做什么,因为这取决于所有这些小部分是如何组合在一起的,这是很难看到的。它看起来就像一大堆小东西。

通过避免大型类中大量耦合代码的意大利面复杂性,您将面临另一种复杂性的风险,其中有许多简单的小类,它们之间的交互非常复杂。

我不认为这是一个致命的缺点- DI仍然是非常值得的。在某种程度上,小班级只做一件事的馄饨风格可能是好的。即使过度,我也不认为它像意大利面条代码那样糟糕。但是要避免它,第一步是要意识到它可能会走得太远。点击链接了解如何避免这种情况。

其他回答

两件事:

它们需要额外的工具支持来检查配置是否有效。

例如,IntelliJ(商业版)支持检查Spring配置的有效性,并将标记出配置中的类型违反等错误。如果没有这种工具支持,就无法在运行测试之前检查配置是否有效。

这就是为什么“蛋糕”模式(Scala社区所熟知)是一个好主意的原因之一:组件之间的连接可以由类型检查器检查。而注释或XML则没有这种好处。

这使得程序的全局静态分析非常困难。

像Spring或Guice这样的框架很难静态地确定容器创建的对象图将是什么样子。尽管它们在容器启动时创建了一个对象图,但它们没有提供有用的api来描述将要创建的对象图。

我不认为存在这样的列表,但是试着阅读这些文章:

DI会模糊代码(如果你没有使用好的IDE) Bob叔叔认为,误用IoC会导致糟糕的代码。 需要注意过度设计和创造不必要的多功能性。

这更像是吹毛求疵。但是依赖注入的一个缺点是,它使开发工具更难推理和导航代码。

具体来说,如果你在代码中控制-单击/命令-单击方法调用,它将带你到接口上的方法声明,而不是具体的实现。

这实际上是松散耦合代码(由接口设计的代码)的缺点,即使不使用依赖注入(即,即使只是使用工厂)也适用。但是依赖注入的出现真正鼓励了松耦合代码的普及,所以我想我应该提到它。

而且,松散耦合代码的好处远远超过这一点,因此我称之为吹毛求疵。尽管我工作了很长时间,知道如果您试图引入依赖注入,可能会遇到这种情况。

事实上,我敢大胆地猜测,对于依赖注入的每一个“缺点”,您都会发现许多优点远远超过它。

这是我自己的第一反应:基本上任何模式都有同样的缺点。

学习是需要时间的 如果误解了,就会弊大于利 如果走到极端,工作量可能会超过收益

基于构造函数的依赖注入(没有神奇的“框架”的帮助)是构造OO代码的一种干净而有益的方式。在我所见过的最好的代码库中,经过多年与Martin Fowler的其他前同事的相处,我开始注意到大多数以这种方式编写的优秀类最终都只有一个doSomething方法。

那么,主要的缺点是,一旦您意识到这只是一种笨拙的、冗长的OO方式,将闭包编写为类,以获得函数式编程的好处,那么您编写OO代码的动机就会迅速消失。