依赖倒置中的 'Inversion' 是什么意思
What is meant by 'Inversion' in Dependency inversion
我正在学习spring。我了解依赖注入。在某些地方我也看到它称为依赖倒置。我知道为什么它被称为注入,但 "inversion" 是什么意思?它实际上反转了哪个依赖项?
好问题 - inversion
这个词有点令人惊讶(因为在应用 DIP 之后,较低级别的依赖模块现在显然不会 depend
在较高级别的调用者上模块,要么 - 调用者和依赖项现在通过额外的抽象更加松散地耦合)。
引用 Robert C Martin 的 original source
One might question why I use the word “inversion”. Frankly, it is because more traditional software development methods, such as Structured Analysis and Design, tend to create software structures in which high level modules depend upon low level modules, and in which abstractions depend upon details. Indeed one of the goals of these methods is to define the subprogram hierarchy that describes how the high level modules make calls to the low level modules. ... Thus, the dependency structure of a well designed object oriented program is “inverted” with respect to the dependency structure that normally results from traditional procedural methods.
阅读 Uncle Bob 关于 DIP 的论文时需要注意的一点是 C++ 没有(at time of writing, still doesn't)有接口,因此在 C++ 中实现这种抽象通常是通过抽象/纯虚拟基实现的class,而在 Java 或 C# 中,松散耦合的抽象通常是通过从依赖项中抽象接口并将更高级别的模块耦合到接口来解耦。
编辑
澄清一下:
"In some place I also see it called dependency inversion"
请注意 Dependency Injection (DI) is ONE of the possible implementations to achieve the Dependency Inversion Principle (DIP) - the "D" in SOLID design principles,因此 DI
和 DIP
不能 完全互换。
其他 DIP 实现包括 Service locator pattern (which is nowadays often regarded as an anti-pattern); and Plugin。
反转:
将依赖管理从应用程序反转到容器(例如Spring)。
依赖注入:
与其编写工厂模式,不如将对象直接注入客户class。所以让客户 class 引用接口,我们应该能够将具体类型注入客户 class。有了这个,客户 class 不需要使用 new 关键字,并且与具体的 classes 完全分离。
那么控制反转 (IoC) 是什么?
在传统编程中,业务逻辑的流程由静态分配给一个对象的对象决定另一个。使用控制反转,流依赖于由汇编程序实例化的对象图并且是通过抽象定义的对象交互成为可能。 绑定过程是通过依赖注入实现的,尽管有人认为服务定位器的使用也提供了控制反转。
作为设计准则的控制反转具有以下目的:
- 某个任务的执行与
实施。
- 每个模块都可以专注于它的设计目的。
- 模块不假设其他系统做什么但依赖于
他们的合同。
- 替换模块对其他模块没有副作用。
有关更多信息,请查看:
Design pattern – Inversion of control and Dependency injection.
据我所知,使用术语“倒置”取决于这样一个事实,即接口被认为是比依赖它的服务更高级别的抽象。 被反转的是抽象依赖的方向:你的服务不再依赖一个低层的东西,而是依赖一个高层的东西。
让我们考虑一个简化的例子。
- 在“糟糕”的应用程序中,
FooService
依赖于 BarDatabase
:我们的服务依赖于数据库实现。值得注意的是,我们的服务依赖于较低级别的 'thing'。
- 在“好的”应用程序中,
FooService
依赖于 DatabaseInterface
,后者又由 BarDatabase
实现。由于接口被认为是比服务更高级的抽象,我们的服务现在依赖于更高级别的 'thing'.
现在,从某种意义上说,依赖的方向性是不变的。实际上,FooService
仍然 间接地 依赖于 BarDatabase
。值得强调的是,当我们说我们已经反转依赖关系时,我们并不是说 BarDatabase
现在以某种方式依赖于 FooService
.
我们的意思只是说,我们的服务现在不再依赖于抽象阶梯较低的东西,而是依赖于更高的东西。我们已经“反转”了我们的服务需要爬升以获得其依赖项的方向。
关于为什么这是一件好事,我将遵从广泛可用的极好的解释,但直觉是 依赖比你自己更抽象的事物会使你与外部事物的耦合度降低,这又与封装和关注点分离等好东西密切相关。
我正在学习spring。我了解依赖注入。在某些地方我也看到它称为依赖倒置。我知道为什么它被称为注入,但 "inversion" 是什么意思?它实际上反转了哪个依赖项?
好问题 - inversion
这个词有点令人惊讶(因为在应用 DIP 之后,较低级别的依赖模块现在显然不会 depend
在较高级别的调用者上模块,要么 - 调用者和依赖项现在通过额外的抽象更加松散地耦合)。
引用 Robert C Martin 的 original source
One might question why I use the word “inversion”. Frankly, it is because more traditional software development methods, such as Structured Analysis and Design, tend to create software structures in which high level modules depend upon low level modules, and in which abstractions depend upon details. Indeed one of the goals of these methods is to define the subprogram hierarchy that describes how the high level modules make calls to the low level modules. ... Thus, the dependency structure of a well designed object oriented program is “inverted” with respect to the dependency structure that normally results from traditional procedural methods.
阅读 Uncle Bob 关于 DIP 的论文时需要注意的一点是 C++ 没有(at time of writing, still doesn't)有接口,因此在 C++ 中实现这种抽象通常是通过抽象/纯虚拟基实现的class,而在 Java 或 C# 中,松散耦合的抽象通常是通过从依赖项中抽象接口并将更高级别的模块耦合到接口来解耦。
编辑 澄清一下:
"In some place I also see it called dependency inversion"
请注意 Dependency Injection (DI) is ONE of the possible implementations to achieve the Dependency Inversion Principle (DIP) - the "D" in SOLID design principles,因此 DI
和 DIP
不能 完全互换。
其他 DIP 实现包括 Service locator pattern (which is nowadays often regarded as an anti-pattern); and Plugin。
反转: 将依赖管理从应用程序反转到容器(例如Spring)。
依赖注入:
与其编写工厂模式,不如将对象直接注入客户class。所以让客户 class 引用接口,我们应该能够将具体类型注入客户 class。有了这个,客户 class 不需要使用 new 关键字,并且与具体的 classes 完全分离。
那么控制反转 (IoC) 是什么?
在传统编程中,业务逻辑的流程由静态分配给一个对象的对象决定另一个。使用控制反转,流依赖于由汇编程序实例化的对象图并且是通过抽象定义的对象交互成为可能。 绑定过程是通过依赖注入实现的,尽管有人认为服务定位器的使用也提供了控制反转。
作为设计准则的控制反转具有以下目的:
- 某个任务的执行与 实施。
- 每个模块都可以专注于它的设计目的。
- 模块不假设其他系统做什么但依赖于 他们的合同。
- 替换模块对其他模块没有副作用。
有关更多信息,请查看:
Design pattern – Inversion of control and Dependency injection.
据我所知,使用术语“倒置”取决于这样一个事实,即接口被认为是比依赖它的服务更高级别的抽象。 被反转的是抽象依赖的方向:你的服务不再依赖一个低层的东西,而是依赖一个高层的东西。
让我们考虑一个简化的例子。
- 在“糟糕”的应用程序中,
FooService
依赖于BarDatabase
:我们的服务依赖于数据库实现。值得注意的是,我们的服务依赖于较低级别的 'thing'。 - 在“好的”应用程序中,
FooService
依赖于DatabaseInterface
,后者又由BarDatabase
实现。由于接口被认为是比服务更高级的抽象,我们的服务现在依赖于更高级别的 'thing'.
现在,从某种意义上说,依赖的方向性是不变的。实际上,FooService
仍然 间接地 依赖于 BarDatabase
。值得强调的是,当我们说我们已经反转依赖关系时,我们并不是说 BarDatabase
现在以某种方式依赖于 FooService
.
我们的意思只是说,我们的服务现在不再依赖于抽象阶梯较低的东西,而是依赖于更高的东西。我们已经“反转”了我们的服务需要爬升以获得其依赖项的方向。
关于为什么这是一件好事,我将遵从广泛可用的极好的解释,但直觉是 依赖比你自己更抽象的事物会使你与外部事物的耦合度降低,这又与封装和关注点分离等好东西密切相关。