Inversion of Control

什么是控制反转?

程序的流程控制权相对于传统的面向过程编程而言发生了反转。下面是维基百科的描述

In software engineering, inversion of control (IoC) is a programming principle. IoC inverts the flow of control as compared to traditional control flow.

看到这里大家可能会觉得云里雾里的…控制反转(Inversion of Control)实际是控制(Control)和反转(Inversion)两个词的组合,所以拨开云雾的关键在于理解控制反转

怎么理解“控制”?

程序的流程控制权,决定程序的运行方式和流程。

举个例子,想必大家都知道,要把大象放进冰箱需要三步:1)打开冰箱门;2)把大象放进冰箱;3)关上冰箱门。用一段代码用表示的话,代码可能长这样

void putElephantToRefrigerator() {打开冰箱门;放进大象;关闭冰箱门;
}int main() {putElephantToRefrigerator();return 0;
}

不过,冰箱可能已经被塞满放不下大象了,我们需要把冰箱里没用的东西清理掉,再把大象团成团放进去,代码会变成这样

void putElephantToRefrigerator() {打开冰箱门;清理冰箱;把大象团成团;放进大象;关闭冰箱门;
}
...

当然,我们完全可以先把大象团成团,像这样

void putElephantToRefrigerator() {把大象团成团;打开冰箱门;清理冰箱;放进大象;关闭冰箱门;
}
...

所以,我们要把大象放进冰箱里都会经过一个流程,目前这个流程是由我们自己控制的。

怎么理解“反转”?

相对于传统的面向过程编程实践而言

  • 程序的流程控制权发生了转变
  • 应用程序与第三方代码之间的调用关系发生了转变

继续看上面的例子,假如我们有一款极其智能的冰箱,不需要手动开门、关门,只要关心放什么东西进去、怎么放进去(nice,事情变得更简单了),代码会变成这样(考虑设计模式-模板方法)

typedef struct AutoRefrigerator;struct MyRefrigerator : AutoRefrigerator {private void putSomething() {...}
}int main() {MyRefrigerator refrigerator;refrigerator.put(elephant);return 0;
}

代码中“refrigerator.put(elephant);”由框架提供,包含多条子语句(open、close、putSomething…),但putSomething没具体实现,需要我们自己定制。

此时,控制程序流程的不是我们的代码而是框架提供的AutoRefrigerator,程序流程控制权发生了反转,控制权由我们自己的代码转移到了框架中

控制反转前后有哪些变化呢?

  • 反转前:我们自己的代码决定程序的工作流程,并调用第三方代码(我们自己的代码是甲方,第三方代码是乙方)
  • 反转后:第三方代码(框架)决定程序的工作流程,并调用我们写的代码(我们自己的代码是乙方,第三方代码是甲方)

可见,在控制反转前我们写的代码会调用第三方代码,而控制反转后则是由第三方代码(框架)调用我们的代码,这种代码调用关系的反转也是控制反转的意义

有什么好处?

好处?怎么可以这么物质?这个问题超纲了,暂且不谈…笔者是个物质的人,所以只谈谈有什么好处。

好处用两个字概括:复用用Paul Graham的话来说,复用就是软件圣杯)。

复用代码有三种方式:类库、框架、设计模式。

  • 类库强调代码复用
    定义一组可复用的代码,供其他程序调用——拿来主义,别人的东西拿来用,用别人的锤子砸核桃。
  • 框架强调设计复用
    定义程序的体系结构,开发人员通过预留的接口插入代码(做填空题)——把自己的锤子装在流水线上,让它砸核桃。
  • 设计模式复用解决方案
    设计模式提供了解决一类问题的有效经验,复用这些经验往往可以很好地解决问题——看别人是怎么砸核桃的,依葫芦画瓢模仿一遍。

控制反转为复用框架提供了可能性。框架定义了解决一类问题的流程、体系结构,但程序的特定细节需要定制,因此框架需要调用我们写的代码,控制反转提供了这种可能性。控制反转和编码原则之一的好莱坞原则(It calls me rather me calling the framework) 也存在着紧密的联系。

另外,按照Martin Fowler的描述,控制反转还有Seperating Configuration from Use的作用。实际上这是一些容器的主要作用(如Spring),而这些容器又不可避免地使用了控制反转。

怎么实践?

说了这么多,又有这么诱人的好处,怎么才能得到它呢?

最简单的实践就是设计模式-模板方法,不过最常见的实践方法还是依赖注入依赖查询
依赖注入(DI:Dependency Inject):被动接收依赖对象,由容器将被依赖对象注入到对象内部;
依赖查询(DL:Dependency Lookup):主动查询依赖对象,由对象自身通过 服务定位器 查询被依赖对象;依赖查询也经常以服务定位器模式(Service Locator)的形式出现。

DI DL
Context依赖各事例 各实例依赖context
通过构造函数、setter函数等容易查看依赖关系 依赖关系不容易查看,需要分析调用locator的源码分析依赖关系
装配关系在业务类外的配置文件中 装配关系在业务类中
被动接收依赖对象 主动查询依赖对象

这两种方式的主要区别在于配置方式不同、获得依赖对象的方式不同。

该怎么决定在代码中使用DI还是DL呢?Martin Fowler有话说

So the decision between locator and injector depends on whether that dependency is a problem.

参考连接

https://www.martinfowler.com/bliki/InversionOfControl.html
https://www.martinfowler.com/articles/injection.html
https://en.wikipedia.org/wiki/Inversion_of_control

浅谈控制反转(IoC)相关推荐

  1. 浅析Spring——控制反转IoC

    目录 1. IoC理论推导 2. 什么是IoC? 3. 引入DI 4. IoC容器 5. 注入对象的四种方法 1.基于接口 2.基于setter 3.基于构造函数 4.基于注解 6. 两种IoC实现方 ...

  2. 依赖倒置(DIP),控制反转(IoC)与依赖注入(DI)

    DIP,IoC与DI概念解析 依赖倒置 DIP(Dependency Inversion Principle) DIP的两大原则: 1.高层模块不应该依赖于低层模块,二者都应该依赖于抽象. 2.抽象不 ...

  3. 控制反转(Ioc)和依赖注入(DI)

    控制反转IOC, 全称 "Inversion of Control".依赖注入DI, 全称 "Dependency Injection". 面向的问题:软件开发 ...

  4. 控制反转IOC与依赖注入DI

    为什么80%的码农都做不了架构师?>>>    1. IoC理论的背景 我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最 ...

  5. 控制反转 java_控制反转( Ioc)快速入门

    2.1 什么是控制反转(IOC:Inverse of Control) IOC反转控制,实际上就是将对象的创建权交给了Spring,程序员无需自己手动实例化对象. 可以看出来工厂的作用就是用来解耦合的 ...

  6. 前端解读控制反转(IOC)

    前言 随着前端承担的职责越来越重,前端应用向着复杂化.规模化的方向发展.大型项目模块化是一种趋势,不可避免模块之间要相互依赖,此外还有很多第三方包.这样的话如何去管理这些繁杂的文件,是一个不可避免的话 ...

  7. 浅谈spring--AOP与IOC / DI

    Spring 是一个开源框架,主要优势是其分层架构,分层架构允许选择使用哪一个组件. 七大模块组成包含Spring Core,AOP,ORM,DAO,Web,Context,Web MVC. Spri ...

  8. PHP依赖注入(DI)和控制反转(IoC)详解

    这篇文章主要介绍了PHP依赖注入(DI)和控制反转(IoC)的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 首先依赖注入和控制反转说的是同一个东西,是一种设计模式,这种设计模式用来减少程 ...

  9. ioc控制反转_深入理解依赖注入(DI)和控制反转(IOC)

    转载本文务必须注明出处.微信号(Yemeir_com).以及添加原文链接. 为什么要使用依赖注入 使用依赖注入(DI)可以使控制者与抽象实现者松耦合,便于单元测试.通过控制反转(IOC)的设计原理来减 ...

最新文章

  1. 注释的编写方式:写明白来龙去脉提高代码产出率
  2. 迪士尼“新顶流”,火不到娱乐圈
  3. Spring Boot 入门与实战笔记
  4. 给大家介绍一下实现Go并发同步原语的基石
  5. myeclipse-common 找不到
  6. BT5新的征程!全民***计划!
  7. 三极管开关为什么工作在饱和区和截至区
  8. 如何关闭135,139,445高危端口
  9. 计算机组装有哪些,DIY电脑组装需要哪些东西
  10. Docker 报错port is already allocated
  11. 千兆SFP光模块可以在万兆SFP+端口上使用吗?
  12. word排版快捷指令_在word文档中如何利用快捷键快速排版呢?
  13. 试题 算法训练 藏匿的刺客
  14. h3c imc-dig 7 linux,H3C iMC iLP安装指导-7.0-5PW100
  15. 非磺化花菁和磺化花菁有机染料Cyanine dyes的说明应用
  16. bp神经网络预测模型优点,什么是BP神经网络模型?
  17. 基于OMAPL138 DSP+ARM的OFDM水声通信系统研究与设计
  18. 华为模拟器ensp——VLAN的配置
  19. 本题要求实现一个函数,将两个字符串连接起来。(strcat)函数实现
  20. MySQL面试2:一张学生表,一张教师表,里面都有Name和Code,写出张三的老师有多少名学生的SQL语句。

热门文章

  1. openharmony中控屏开发6:H3.95超级面板的电路设计1
  2. 一些自己面试unity3D 程序员的面经
  3. 第二次量产成功:KingSton DT 101 G2 8G的量产经历
  4. 部署https(ssl)后设置301跳转将http跳转到https
  5. vim快捷键的使用案例
  6. android计步器清零,手机计步器的数字如何清零
  7. VISA 函数的运用解释
  8. uart接口的时序分析
  9. 左手万事达、右手支付宝,被“逼上梁山”的美团支付该何去何从?
  10. java基础-一次越南语乱码经历