控制反转(IoC),依赖反转(DI)和解耦的区别

97

我正在阅读关于依赖反转解耦的理论,但我看不出两者之间的区别。

依赖反转讲述了如何解耦功能组件,使得高层次的组件不依赖于低层次的组件。

解耦也在讲同样的事情以及如何实现它。但是,我们有 IoC容器 进一步混淆了问题。为什么它们不被称为 依赖反转容器 ,甚至更好的是 依赖注入容器 ,因为它们提供了独立组件的运行时耦合?

接下来是控制反转。它基本上与依赖反转相同,不是吗?为什么有三个描述同一事物的术语?还是我眼瞎?

  1. 这三者之间有什么不同?
  2. IoC容器中的IoC是什么意思?

@ Anton Gogolev:解耦合的拼写应该多一个“o”:http://en.wikipedia.org/wiki/Decoupling#Software_Development - Robert Koritnik
4个回答

97

解耦是适用于许多领域的普遍原则。 依赖倒置 是解耦的一种具体形式,它通过将系统的高层次与低层次分离成库并使用接口来解除它们之间的联系。这允许您替换系统的低级部分而不需要进行重大改动。

例如,高层次的系统部分可以使用IoC容器而不是创建低层次类的具体实例,以解耦对象的创建方式。

控制反转是框架库使用的一种设计原则,它允许框架从应用程序中重新获得一些控制权。例如,窗口框架可能在发生某些用户界面事件时回调应用程序代码。Martin Fowler使用术语Hollywood Principle,即“不要打电话给我们,我们会打电话给你”。解耦是控制反转的重要组成部分。

但是,IoC容器与控制反转有什么关系?引用Martin Fowler的话

控制反转是一个过于通用的术语,因此人们会感到困惑。因此,经过与各种IoC倡导者的大量讨论,我们选择了名称“依赖注入”。

(请注意,Martin Fowler谈论的是依赖注入而不是依赖倒置。)

IoC容器有助于实现依赖注入,也许更好的术语应该是依赖注入容器。但是,IoC容器的名称似乎很有说服力。依赖注入是依赖倒置的重要组成部分,但是使用IoC容器进行依赖注入可能会令人困惑,因为控制反转是一个更广泛和通用的原则。

您指出命名不太一致,但这并不是一个大问题,因为这些术语已经被独立发明和使用,即使它们重叠。


我同意,尽管我不会使用“IoC容器”这个术语,因为正如你所说,它并不是真正正确的。我认为在这里遵循(不正确的)流行命名方案并不重要,因为任何理解DI容器原则的人都应该能够理解正确的命名方式。 - Andrey Shchekin

53

依赖注入通过使用控制反转实现解耦合


1
-1 这实际上将“依赖注入”这个术语与“控制反转”联系在一起。依赖注入本身就是一种解耦技术。 - Mauricio Scheffer
3
@Mauricio:我认为依赖注入根本不是解耦或解耦技术。 DI为耦合的组件提供了解耦的手段。而不是相反。 - Robert Koritnik
7
依赖注入是控制反转的一种形式,但并不一定能实现很好的解耦。依赖反转是实现解耦的关键,并且使用带有控制反转容器的依赖注入可以方便地实现依赖反转。 - ben
天啊,话不多说 :( 鲍里斯写得很好。做每件事情的方法太多了。重要的是团队内部有信任和尊重。从最纯粹的角度来看,如果团队合作达到最佳状态并且对自己的工作充满信心,那么软件设计原则和相关书籍就没有用武之地了。 - Michael Socha
我更喜欢:依赖倒置是一种解耦的方式,可以通过依赖注入来实现。 - Delmo

33
我发现来自martinfowler.com上DIP in the Wild文章的以下解释很容易理解(这里DI = 依赖注入,DIP = 依赖倒置原则,IoC = 控制反转):
DI是关于一个对象如何获取依赖项。当外部提供依赖项时,系统使用DI。IoC是关于谁启动调用。如果您的代码启动了调用,则它不是IoC;如果容器/系统/库回调到您提供的代码,则它是IoC。
另一方面,DIP关于从您的代码发送到正在调用的对象的消息的抽象级别。(...)DI是关于连线的,IoC是关于方向的,而DIP是关于对象形状[依赖的对象]的。

5
DI是关于连接,IoC关注方向,而DIP则关注代码所依赖的对象的形状。这是一个很好的句子 ;) - Amir Ziarati
2
我觉得最后一句话中的“shape”这个词有些令人困惑。它似乎没有比已经陈述的更多的内容:DIP是关于抽象化的。我会说IoC是关于“谁”,DIP是关于“什么”,而DI则是关于“如何”。 “谁”控制依赖? 依赖项抽象了什么? 依赖项如何交付? - jaco0646

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接