IoC、DIP

IoC 理解

IoC 全称 inversion of control,控制反转,它是一种编程原则。可以将它拆成两个词语分别理解。控制的是什么?反转指由谁转移到谁?

在传统的面向过程编程中,当我们想要实现一些业务逻辑的时候,还需要自己去调用一些可复用的库来实现一些其它非业务特定的功能(例如我们的程序涉及网络交互时,需要解析网络协议等操作),从而将整个程序完整地构建起来,想要实现我们要的业务功能,我们要实现一整套程序的所有 控制流 。而在 IoC 思想中,当我们要实现某个具体功能的时候,我们假设 IoC 框架已经存在(无论是要我们自己编写还是已经有现成的框架,此时我们并不关心它如何实现,对于我们来说它是一个透明的介入者或者一个黑盒),这样我们在实现某个具体功能的时候,只需要注册(插入、绑定、扩展)我们编写的特定功能代码即可。在当前这个时间点(阶段),整个程序的其它流程(程序启动、对象创建、对象绑定等等)我们并不需要关心,这些都由 IoC 框架来控制。而 IoC 框架本身又是程序的一段指令,就好像我们插入的功能代码反而被程序"神秘地"调起了(钩子/hook、插件思维),所以称为控制反转。

上面提到的"特定功能代码"可以是程序中实现特定功能的任意模块(技术模块、非技术的业务模块都可以),所以 IoC 框架可以视为一个声明了各个模块的实现标准、插入方式、调用时机(生命周期/策略模式)、调用入口(接口)的主干,基于这个框架,我们的程序会变得更灵活、更可扩展。

其实这里是相对难理解的地方,框架的代码也是程序员来编写的,怎么就反转了?这里有个重要的前提,我们在当前阶段只关心某个特定功能的实现,其它功能和主干流程如何实现我们不关心,由框架控制,我们只关心框架给我们的功能模块定义的插入标准是怎样的,按照该标准实现即可,也就是说在当前阶段,我们如何实现该功能收到了框架的制约、控制。

IoC 例子

对象创建、图形化、云原生服务编排等我们经常接触到的经典的实现,都是 IoC 的体现。

另外,相关的概念还有 事件驱动编程,也是 IoC 的体现,我们只管发布事件或者处理事件,至于事件如何实现触达、绑定处理者,是框架的事情。

所以我们在日常业务编码中,也可以多多进行 IoC 的思考,我们的业务是否比较复杂、多变,变化的是哪些,是否具备 IoC 构建的条件使得业务代码变得更灵活。

IoC 带来的好处

以下是 IoC 要达到的目标,也即它带来的好处:

  • 将特定功能的执行和实现解耦开来。
  • 使某个模块专注于它要实现的功能上,无需关心其它功能如何实现。
  • 使得整个程序系统规范化,各模块以及外部系统依赖 约定 协作。
  • 防止对一个模块进行替换的时候对外围产生影响(side effects)。

实现 IoC

在面向对象编程中,以下是一些实现 IoC 框架的方法:

控制反转(IoC)和依赖反转(DIP)

和 IoC 相关的概念还有一个是 DIP(Dependency Inversion Principle),依赖反转原则。依赖反转原则关心的对于高低层间的依赖的解耦,通过在高低层间引入一层抽象层,双方依赖抽象层进行联系,描述如下:

  1. High-level modules should not depend on low-level modules. Both should depend on abstractions (e.g., interfaces).
  2. Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions.

基于面向对象编程语言提供的"抽象"的语法,例如 Java 中接口,即可实现 DIP。

利用 DIP、工厂模式、策略模式、依赖注入、面向配置,即可使得对象的创建具备灵活性。相较于 DIP,IoC 关心的是更宽泛、更高层的事情。类似 Servlet,即是 DIP 的体现也是 IoC 的体现,Tomcat Web容器和我们的 Web 应用程序之间都依赖了 Servlet 规范,是 DIP 的体现,我们基于 Servlet 进行编程实现具体的业务逻辑,在特定场景下被 Tomcat 调起,即是 IoC 的体现。

terms

编程范式(Programming paradigm)

  • impreactive programming 命令(指令)式编程:整个程序完完全全由程序员组装一个个指令、例程、库构成,整个流程由程序员来控制。
  • Declarative programming 声明式编程:程序员指定一些特定编码,由框架/编译器/解释器等识别编码后对编码后面代表的逻辑(调用某个例程/创建某个数据结构、域对象等)进行组装构成程序。程序的代码不再是冗长的控制流程描述,而是一组描述了程序应该执行什么动作的指令组成,这区别于命令式编程。同时无 side effects 也是它的特征。
    • SQL
    • 标记语言:HTML、XML
    • functional programming 函数式编程 :无 side effects(函数参数都是值传递,变量的最大作用域就是函数)、函数可作为参数传递可作为返回值、程序逻辑通过应用函数和组装函数描述… 比如科学计算、数据处理、统计分析等这些领域,程序往往比较容易用数学表达式来表示,比起非函数式编程,实现同样的功能,函数式编程可以用很少的代码就能搞定。如果使用面向对象编程来实现,需要较大的代码量进行转换
  • Object-oriented programming 面向对象编程 :数据行为不分离形成一个业务 domain(域),程序员通过组装这些 domain 构成程序。
  • event-driven programming 事件驱动编程:程序(容器)本身已经存在(框架定义了主流程),程序员只需要对事件和时间处理器注册到框架(程序/容器)即可构建自己的业务程序。(钩子思想)
  • Literate programming 面向人类语言编程:计算机程序逻辑由人类自然语言编写,例如英文,并携带着大量的宏或者源码片段。

reference

wiki:Inversion of Control

TutorialsTeacher:Inversion of Control :比较完整地表述了如何用 IoC 实现一套解耦的程序。


   转载规则


《IoC、DIP》 阿钟 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录