IOC理解

成功就是简单道理的深刻理解与灵活运用

前不久,阿里大牛虾总在群里抛出一个问题:“从深层次讲解一下如何理解IOC,IOC和DI是一回事吗?”

这个问题真是让人平静而又不平静

平静源于此问题就像问中国人怎么使用筷子,天天使用筷子,难道还不会使用筷子?

但又不平静,你能写出一份详细的说明书,让一个不会使用筷子的人按此说明成功地使用上筷子吗?


天天使用spring,是否还记得那些简单原理?现如今会写六种回字的你,还记得回的本意吗?

那些曾经刻骨铭心的记忆,你有多久没有想起了


IOC

不管是平时交流,还是面试,当谈谈spring时,除了api使用,最主要还是要聊聊IOC

Ioc—Inversion of Control,即“控制反转”

从语文的角度解析一下,如果“控制”当成一个动作,那就需要完善主语与宾语,也就是“谁”控制了“谁”;

“反转”:没有反转是什么情况,what反转,why反转,how反转

分两种情况讨论,1、没有IOC容器,2、有IOC容器

没有IOC容器

参与者

回答“谁”控制了“谁”中的两个“谁”

抽象讲:某个对象A控制了另一个某对象B

宏观讲 某个对象A可能就是应用程序,比如读取或者修改一个文件,那么此处的文件也就是某对象B了

微观讲,objectA 操作了 objectB,比如给objectB的属性赋值

从由内向外的角度 由两个参与者:某一对象(任意的对象类),以及对象外的各种资源(需要的其它对象、或者是对象需要的文件资源等等)

控制

常规情况下的应用程序,如果要在A里面使用C,当然是直接去创建C的对象,也就是说,是在A类中主动去获取所需要的外部资源C

1
2
3
A a = new AImpl(); 
C c = new CImpl(); 
a.setC(c);

当前类控制了一切:主动实例化、获取依赖、主动装配

这儿示例简单了点,一些项目会使用上Factory模式,让程序更面向接口,最小化变化,最大化地“开-闭”原则

但不管如何,还是会面临一些问题:

  1. 更换实现需要重新编译源代码
  2. 依赖变更很难更换实现、难于测试
  3. 耦合实例生产者和实例消费者

有IOC容器

引入IOC容器

参与者

除了对象与对象外的资源,增加了IOC容器

控制

引入IOC容器后,就不再是直接控制了,而是被动等待,等待IoC/DI的容器获取一个C的实例,然后反向的注入到A类中

此时,对象不再主动去new,而IoC容器来创建这些对象,即由Ioc容器来控制对象的创建;

再来看“谁”控制了“谁”?

IoC 容器控制了对象;控制什么?主要控制了外部资源获取(不只是对象包括比如文件等)

反转

1
2
3
A a = new AImpl(); 
C c = new CImpl(); 
a.setC(c);

还是看这段代码,包含了 主动实例化、获取依赖主动装配

根据【控制】,IOC做到了主动实例化、获取依赖;而【反转】体现在了主动装配这一点

传统应用程序是由我们自己在对象中主动控制去直接获取并set依赖对象,是为【正转】;

而【反转】则是由容器来帮忙创建及注入依赖对象;

为何是反转?

因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取、装配被反转了


IOC总结

IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”;即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找

传统关系转变成

IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC思想中,应用程序就变成被动的了,被动的等待IoC容器来创建并注入它所需要的资源了

这么小小的一个改变其实是编程思想的一个大进步,这样就有效的分离了对象和它所需要的外部资源,使得它们松散耦合,有利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活

DI

DI—Dependency Injection,即“依赖注入”:组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。

通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。  

理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”

那我们来深入分析一下:

  • 谁依赖于谁:当然是应用程序依赖于IoC容器;  
  • 为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;  
  • 谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;  
  • 注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)

IOC VS DI

IoC和DI什么关系?

貌似是个仁者见仁的问题,有人认为两者是同一个东西,也有人认为是不同的概念;

摘抄一些见解


根据上面的讲述,应该能看出来,依赖注入和控制反转是对同一件事情的不同描述,从某个方面讲,就是它们描述的角度不同。依赖注入是从应用程序的角度在描述,可以把依赖注入描述完整点:应用程序依赖容器创建并注入它所需要的外部资源;而控制反转是从容器的角度在描述,描述完整点:容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源。


DI仅是用一个单独的对象(装配器)来装配对象之间的依赖关系,一般有setter、构造、接口注入等,与IOC不是一回事,仅是IOC依赖管理层面的东西


IOC是思想,DI是IOC的具体实现

也可看看鼻祖Martin Fowler的表述

As a result I think we need a more specific name for this pattern. Inversion of Control is too generic a term, and thus people find it confusing. As a result with a lot of discussion with various IoC advocates we settled on the name Dependency Injection.

参考资料

Inversion of Control Containers and the Dependency Injection pattern
IOC是什么

公众号:码农戏码
欢迎关注微信公众号『码农戏码』