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

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


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


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


当前回答

它可以增加应用启动时间,因为IoC容器应该以适当的方式解析依赖关系,有时需要进行多次迭代。

其他回答

If you're using DI without an IoC container, the biggest downside is you quickly see how many dependencies your code actually has and how tightly coupled everything really is. ("But I thought it was a good design!") The natural progression is to move towards an IoC container which can take a little bit of time to learn and implement (not nearly as bad as the WPF learning curve, but it's not free either). The final downside is some developers will begin to write honest to goodness unit tests and it will take them time to figure it out. Devs who could previously crank something out in half a day will suddenly spend two days trying to figure out how to mock all of their dependencies.

类似于马克·西曼(Mark Seemann)的回答(现已删除;只有超过1万个声誉点),底线是你花时间成为一个更好的开发人员,而不是把代码拼凑在一起,然后把它扔出去/投入生产。你的企业更愿意选择哪一种?只有你能回答这个问题。

仅仅通过实现依赖注入就实现了代码的解耦,而没有实际解耦。我认为这是DI最危险的地方。

当您不断地使用技术来处理静态类型时,静态类型语言的假定好处似乎大大减少了。我刚刚采访的一家大型Java商店正在用静态代码分析绘制他们的构建依赖关系……它必须解析所有的Spring文件才能有效。

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

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

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

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

我发现构造函数注入会导致构造函数又大又丑(我在整个代码库中都使用它——也许我的对象太细了?)此外,有时使用构造函数注入会导致可怕的循环依赖(尽管这种情况非常罕见),因此您可能会发现自己必须在更复杂的系统中拥有某种就绪状态生命周期,并进行几轮依赖注入。

然而,我更喜欢构造器注入而不是setter注入,因为一旦我的对象被构造,那么我就可以毫无疑问地知道它处于什么状态,它是在单元测试环境中还是加载到某个IOC容器中。这,以一种迂回的方式说,我觉得是setter注入的主要缺点。

(作为旁注,我确实发现整个主题相当“宗教”,但你的成就将随着开发团队的技术狂热程度而变化!)