依赖反转原则IOC 你真的懂吗?

264 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情

问题

  • “依赖反转”这个概念指的是“谁跟谁”的“什么依赖”被反转了?“反转”两个字该如何理解?
  • 我们还经常听到另外两个概念: “控制反转”和“依赖注入”。这两个概念跟“依赖反转”有什么区别和联系呢?它们说的是同一个事情吗?
  • 如果你熟悉 Java 语言,那 Spring 框架中的 IOC 跟这些概念又有什么关系呢?

控制反转IOC

定义

控制反转的英文翻译是 Inversion Of Control,缩写为 IOC

通过框架来实现“控制反转”的例子。框架提供了一个可扩展的代码骨架,用来组装对象、管理整个执行流程。程序员利用框架进行开发的时候,只需要往预留的扩展点上,添加跟自己业务相关的代码,就可以利用框架来驱动整个程序流程的执行

“控制”指的是对程序执行流程的控制,而“反转”指的是在没有使用框架之前,程序员自己控制整个程序的执行。在使用框架之后,整个程序的执行流程可以通过框架来控制。流程的控制权从程序员“反转”到了框架。

实现控制反转的方法有很多,还有马上要讲到的依赖注入等方法,所以,控制反转并不是一种具体的实现技巧,而是一个比较笼统的设计思想,一般用来指导框架层面的设计。

精选留言

  1. 控制反转,是把对于核心业务流程无关的处理流程(除了doTest为核心业务逻辑,其余都是流程),由程序猿手动编码实现,“反转”为由框架来实现,把流程的控制权交给了框架,这是大多数框架能够提升开发效率的根本原因:大大降低了非核心业务逻辑的开发量。
  2. 可扩展框架用来包含业务逻辑流程的代码,将业务控制流程浓缩到框架内。外部只希望调用框架的开关,而不希望看到程序代码核心实现,因为自己需要通过调用各种代码核心实现来执行流程。而这种事情对不熟悉业务逻辑的用户来说是非常困难调用的,即使是程序员,如果业务逻辑变多了,每次实现都需要做很多铺垫,也是非常麻烦的一件事。所以就干脆直接将控制调用这一部分放在框架里,自己只需要管理调用即可。

依赖注入DI

和控制反转相反,依赖注入是具体的代码实现,具体的编码技巧。依赖注入的英文翻译是 Dependency Injection,缩写为 DI。对于这个概念,有一个非常形象的说法,那就是:依赖注入是一个标价 25 美元,实际上只值 5 美分的概念。也就是说,这个概念听起来很“高大上”,实际上,理解、应用起来非常简单。

定义

那到底什么是依赖注入呢?我们用一句话来概括就是:

不通过 new() 的方式在类内部创建依赖类对象,而是将依赖的类对象在外部创建好之后,通过构造函数、函数参数等方式传递(或注入)给类使用。

好处

通过依赖注入的方式来将依赖的类对象传递进来,这样就提高了代码的扩展性,我们可以灵活地替换依赖的类。这一点在我们之前讲“开闭原则”的时候也提到过。

依赖注入框架DI Framework

为什么要出现DI框架

在实际的软件开发中,一些项目可能会涉及几十、上百、甚至几百个类,类对象的创建和依赖注入会变得非常复杂。如果这部分工作都是靠程序员自己写代码来完成,容易出错且开发成本也比较高。而对象创建和依赖注入的工作,本身跟具体的业务无关,我们完全可以抽象成框架来自动完成。

做法

只需要通过依赖注入框架提供的扩展点,简单配置一下所有需要创建的类对象、类与类之间的依赖关系,就可以实现由框架来自动创建对象、管理对象的生命周期、依赖注入等原本需要程序员来做的事情。

也叫控制翻转容器,因为将创建注入的流程交给了框架去实现

依赖反转原则DIP

前面讲了控制反转、依赖注入、依赖注入框架,现在,我们来讲一讲今天的主角:依赖反转原则。依赖反转原则的英文翻译是 Dependency Inversion Principle,缩写为 DIP。中文翻译有时候也叫依赖倒置原则。

定义

原汁原味的描述:

High-level modules shouldn’t depend on low-level modules. Both modules should depend on abstractions. In addition, abstractions shouldn’t depend on details. Details depend on abstractions.

中文,大概意思就是 :高层模块(high-level modules)不要依赖低层模块(low-level) 。高层模块和低层模块应该通过抽象(abstractions)来互相依赖。除此之外,抽象(abstractions)不要依赖具体实现细节(details),具体实现细节(details)依赖抽象(abstractions)。