成功就是简单道理的深刻理解与灵活运用
前不久,阿里大牛虾总在群里抛出一个问题:“从深层次讲解一下如何理解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
A a = new AImpl(); C c = new CImpl(); a.setC(c);
当前类控制了一切:主动实例化、获取依赖、主动装配
这儿示例简单了点,一些项目会使用上Factory模式,让程序更面向接口,最小化变化,最大化地“开-闭”原则
但不管如何,还是会面临一些问题:
- 更换实现需要重新编译源代码
- 依赖变更很难更换实现、难于测试
- 耦合实例生产者和实例消费者
有IOC容器
引入IOC容器
参与者
除了对象与对象外的资源,增加了IOC容器
控制
引入IOC容器后,就不再是直接控制了,而是被动等待,等待IoC/DI的容器获取一个C的实例,然后反向的注入到A类中
此时,对象不再主动去new,而IoC容器来创建这些对象,即由Ioc容器来控制对象的创建;
再来看“谁”控制了“谁”?
IoC 容器控制了对象;控制什么?主要控制了外部资源获取(不只是对象包括比如文件等)
反转
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是什么