正文
1. IoC理论的背景

我们都知道,在采取面向工具方法设计的软件系统中,它的底层实现都是由N个工具组成的,所有的工具通过彼此的互助,终极实现系统的业务逻辑。
图1:软件系统中耦合的工具
如果我们打开机器式腕表的后盖,就会看到与上面类似的环境,各个齿轮分别带动时针、分针和秒针顺时针旋转,从而在表盘上产生精确的韶光。
图1中描述的便是这样的一个齿轮组,它拥有多个独立的齿轮,这些齿轮相互啮合在一起,协同事情,共同完成某项任务。我们可以看到,在这样的齿轮组中,如果有一个齿轮出了问题,就可能会影响到全体齿轮组的正常运转。
齿轮组中齿轮之间的啮合关系,与软件系统中工具之间的耦合关系非常相似。工具之间的耦合关系是无法避免的,也是必要的,这是协同事情的根本。现在,伴随着工业级运用的规模越来越弘大,工具之间的依赖关系也越来越繁芜,常常会涌现工具之间的多重依赖性关系,因此,架构师和设计师对付系统的剖析和设计,将面临更大的寻衅。工具之间耦合度过高的系统,一定会涌现牵一发而动全身的环境。
图2:工具之间繁芜的依赖关系
耦合关系不仅会涌如今工具与工具之间,也会涌如今软件系统的各模块之间,以及软件系统和硬件系统之间。如何降落系统之间、模块之间和工具之间的耦合度,是软件工程永久追求的目标之一。为理解决工具之间的耦合度过高的问题,软件专家Michael Mattson提出了IOC理论,用来实现工具之间的“解耦”,目前这个理论已经被成功地运用到实践当中,很多的J2EE项目均采取了IOC框架产品Spring。
2. 什么是掌握反转(IoC)
IOC是Inversion of Control的缩写,多数书本翻译成“掌握反转”,还有些书本翻译成为“掌握反向”或者“掌握颠倒”。
1996年,Michael Mattson在一篇有关磋商面向工具框架的文章中,首先提出了IOC 这个观点。对付面向工具设计及编程的基本思想,前面我们已经讲了很多了,不再赘述,大略来说便是把繁芜系统分解成相互互助的工具,这些工具类通过封装往后,内部实现对外部是透明的,从而降落理解决问题的繁芜度,而且可以灵巧地被重用和扩展。IOC理论提出的不雅观点大体是这样的:借助于“第三方”实现具有依赖关系的工具之间的解耦,如下图:
图3:IOC解耦过程
大家看到了吧,由于引进了中间位置的“第三方”,也便是IOC容器,使得A、B、C、D这4个工具没有了耦合关系,齿轮之间的传动全部依赖“第三方”了,全部工具的掌握权全部上缴给“第三方”IOC容器,以是,IOC容器成了全体系统的关键核心,它起到了一种类似“粘合剂”的浸染,把系统中的所有工具粘合在一起发挥浸染,如果没有这个“粘合剂”,工具与工具之间会彼此失落去联系,这便是有人把IOC容器比喻成“粘合剂”的由来。
我们再来做个试验:把上图中间的IOC容器拿掉,然后再来看看这套系统:
图4:拿掉IoC容器后的系统
我们现在看到的画面,便是我们要实现全体系统所须要完成的全部内容。这时候,A、B、C、D这4个工具之间已经没有了耦合关系,彼此毫无联系,这样的话,当你在实现A的时候,根本无须再去考虑B、C和D了,工具之间的依赖关系已经降落到了最低程度。以是,如果真能实现IOC容器,对付系统开拓而言,这将是一件多么美好的事情,参与开拓的每一成员只要实现自己的类就可以了,跟别人没有任何关系!
我们再来看看,掌握反转(IOC)到底为什么要起这么个名字?我们来比拟一下:
软件系统在没有引入IOC容器之前,如图1所示,工具A依赖于工具B,那么工具A在初始化或者运行到某一点的时候,自己必须主动去创建工具B或者利用已经创建的工具B。无论是创建还是利用工具B,掌握权都在自己手上。
软件系统在引入IOC容器之后,这种环境就完备改变了,如图3所示,由于IOC容器的加入,工具A与工具B之间失落去了直接联系,以是,当工具A运行到须要工具B的时候,IOC容器会主动创建一个工具B注入到工具A须要的地方。
通过前后的比拟,我们不丢脸出来:工具A得到依赖工具B的过程,由主动行为变为了被动行为,掌握权颠倒过来了,这便是“掌握反转”这个名称的由来。
3. IOC的别名:依赖注入(DI)
2004年,Martin Fowler磋商了同一个问题,既然IOC是掌握反转,那么到底是“哪些方面的掌握被反转了呢?”,经由详细地剖析和论证后,他得出了答案:“得到依赖工具的过程被反转了”。掌握被反转之后,得到依赖工具的过程由自身管理变为了由IOC容器主动注入。于是,他给“掌握反转”取了一个更得当的名字叫做“依赖注入(Dependency Injection)”。他的这个答案,实际上给出了实现IOC的方法:注入。所谓依赖注入,便是由IOC容器在运行期间,动态地将某种依赖关系注入到工具之中。
以是,依赖注入(DI)和掌握反转(IOC)是从不同的角度的描述的同一件事情,便是指通过引入IOC容器,利用依赖关系注入的办法,实现工具之间的解耦。
我们举一个生活中的例子,来帮助理解依赖注入的过程。大家对USB接口和USB设备该当都很熟习吧,USB为我们利用电脑供应了很大的方便,现在有很多的外部设备都支持USB接口。
图5:USB接口和USB设备
现在,我们利用电脑主机和USB接口来实现一个任务:从外部USB设备读取一个文件。
电脑主机读取文件的时候,它一点也不会关心USB接口上连接的是什么外部设备,而且它确实也无须知道。它的任务便是读取USB接口,挂接的外部设备只要符合USB接口标准即可。以是,如果我给电脑主机连接上一个U盘,那么主机就从U盘上读取文件;如果我给电脑主机连接上一个外置硬盘,那么电脑主机就从外置硬盘上读取文件。挂接外部设备的权力由我作主,即掌握权归我,至于USB接口挂接的是什么设备,电脑主机是决定不了,它只能被动的接管。电脑主机须要外部设备的时候,根本不用它见告我,我就会主动帮它挂上它想要的外部设备,你看我的做事是多么的到位。这便是我们生活中常见的一个依赖注入的例子。在这个过程中,我就起到了IOC容器的浸染。
通过这个例子,依赖注入的思路已经非常清楚:当电脑主机读取文件的时候,我就把它所要依赖的外部设备,帮他挂接上。全体外部设备注入的过程和一个被依赖的工具在系统运行时被注入其余一个工具内部的过程完备一样。
我们把依赖注入运用到软件系统中,再来描述一下这个过程:
工具A依赖于工具B,当工具 A须要用到工具B的时候,IOC容器就会立即创建一个工具B送给工具A。IOC容器便是一个工具制造工厂,你须要什么,它会给你送去,你直策应用就行了,而再也不用去关心你所用的东西是如何制成的,也不用关心末了是怎么被销毁的,这统统全部由IOC容器包办。
在传统的实现中,由程序内部代码来掌握组件之间的关系。我们常常利用new关键字来实现两个组件之间关系的组合,这种实现办法会造成组件之间耦合。IOC很好地办理了该问题,它将实现组件间关系从程序内部提到外部容器,也便是说由容器在运行期将组件间的某种依赖关系动态注入组件中。
4. IOC为我们带来了什么好处
我们还是从USB的例子提及,利用USB外部设备比利用内置硬盘,到底带来什么好处?
第一、USB设备作为电脑主机的外部设备,在插入主机之前,与电脑主机没有任何的关系,只有被我们连接在一起之后,两者才发生联系,具有干系性。以是,无论两者中的任何一方涌现什么的问题,都不会影响另一方的运行。这种特性表示在软件工程中,便是可掩护性比较好,非常便于进行单元测试,便于调试程序和诊断故障。代码中的每一个Class都可以单独测试,彼此之间互不影响,只要担保自身的功能无误即可,这便是组件之间低耦合或者无耦合带来的好处。
第二、USB设备和电脑主机的之间无关性,还带来了其余一个好处,生产USB设备的厂商和生产电脑主机的厂商完备可以是互不相关的人,各干各事,他们之间唯一须要遵守的便是USB接口标准。这种特性表示在软件开拓过程中,好处可是太大了。每个开拓团队的成员都只须要关心实现自身的业务逻辑,完备不用去关心其它的人事情进展,由于你的任务跟别人没有任何关系,你的任务可以单独测试,你的任务也不用依赖于别人的组件,再也不用扯不清任务了。以是,在一个大中型项目中,团队成员分工明确、任务明晰,很随意马虎将一个大的任务划分为眇小的任务,开拓效率和产品质量必将得到大幅度的提高。
第三、同一个USB外部设备可以插接到任何支持USB的设备,可以插接到电脑主机,也可以插接到DV机,USB外部设备可以被反复利用。在软件工程中,这种特性便是可复用性好,我们可以把具有普遍性的常用组件独立出来,反复利用到项目中的其它部分,或者是其它项目,当然这也是面向工具的基本特色。显然,IOC不仅更好地贯彻了这个原则,提高了模块的可复用性。符合接口标准的实现,都可以插接到支持此标准的模块中。
第四、同USB外部设备一样,模块具有热插拔特性。IOC天生工具的办法转为外置办法,也便是把工具天生放在配置文件里进行定义,这样,当我们改换一个实现子类将会变得很大略,只要修正配置文件就可以了,完备具有热插拨的特性。
以上几点好处,难道还不敷以打动我们,让我们在项目开拓过程中利用IOC框架吗?
5. IOC容器的技能阐发
IOC中最基本的技能便是“反射(Reflection)”编程,目前.Net C#、Java和PHP5等措辞均支持,个中PHP5的技能书本中,有时候也被翻译成“映射”。有关反射的观点和用法,大家该当都很清楚,普通来讲便是根据给出的类名(字符串办法)来动态地天生工具。这种编程办法可以让工具在天生时才决定到底是哪一种工具。反射的运用是很广泛的,很多的成熟的框架,比如象Java中的Hibernate、Spring框架,.Net中 NHibernate、Spring.Net框架都是把“反射”做为最基本的技能手段。
反射技能实在很早就涌现了,但一贯被忽略,没有被进一步的利用。当时的反射编程办法相对付正常的工具天生办法要慢至少得10倍。现在的反射技能经由改良优化,已经非常成熟,反射办法天生工具和常日工具天生办法,速率已经相差不大了,大约为1-2倍的差距。
我们可以把IOC容器的事情模式看做是工厂模式的升华,可以把IOC容器看作是一个工厂,这个工厂里要生产的工具都在配置文件中给出定义,然后利用编程措辞的的反射编程,根据配置文件中给出的类名天生相应的工具。从实现来看,IOC是把以前在工厂方法里写去世的工具天生代码,改变为由配置文件来定义,也便是把工厂和工具天生这两者独立分别隔来,目的便是提高灵巧性和可掩护性。
6. IOC容器的一些产品
Sun ONE技能体系下的IOC容器有:轻量级的有Spring、Guice、Pico Container、Avalon、HiveMind;重量级的有EJB;不轻不重的有JBoss,Jdon等等。Spring框架作为Java开拓中SSH(Struts、Spring、Hibernate)三剑客之一,大中小项目中都有利用,非常成熟,运用广泛,EJB在关键性的工业级项目中也被利用,比如某些电信业务。
.Net技能体系下的IOC容器有:Spring.Net、Castle等等。Spring.Net是从Java的Spring移植过来的IOC容器,Castle的IOC容器便是Windsor部分。它们均是轻量级的框架,比较成熟,个中Spring.Net已经被逐渐运用于各种项目中。
7. 利用IOC框架该当把稳什么
利用IOC框架产品能够给我们的开拓过程带来很大的好处,但是也要充分认识引入IOC框架的缺陷,做到心中有数,杜绝滥用框架。
第一、软件系统中由于引入了第三方IOC容器,天生工具的步骤变得有些繁芜,本来是两者之间的事情,又凭空多出一道手续,以是,我们在刚开始利用IOC框架的时候,会觉得系统变得不太直不雅观。以是,引入了一个全新的框架,就会增加团队成员学习和认识的培训本钱,并且在往后的运行掩护中,还得让新加入者具备同样的知识体系。
第二、由于IOC容器天生工具是通过反射办法,在运行效率上有一定的损耗。如果你要追求运行效率的话,就必须对此进行权衡。
第三、详细到IOC框架产品(比如:Spring)来讲,须要进行大量的配制事情,比较繁琐,对付一些小的项目而言,客不雅观上也可能加大一些事情本钱。
第四、IOC框架产品本身的成熟度须要进行评估,如果引入一个不成熟的IOC框架产品,那么会影响到全体项目,以是这也是一个隐性的风险。
我们大体可以得出这样的结论:一些事情量不大的项目或者产品,不太适宜利用IOC框架产品。其余,如果团队成员的知识能力欠缺,对付IOC框架产品缺少深入的理解,也不要贸然引入。末了,特殊强调运行效率的项目或者产品,也不太适宜引入IOC框架产品,象WEB2.0网站便是这种情形。
欢迎在留言区留下你的不雅观点,一起谈论提高。如果本日的文章让你有新的启示,学习能力的提升上有新的认识,欢迎转发分享给更多人。
猜你还想看
阿里、腾讯、百度、华为、京东最新口试题搜集
Redis Sentinel 架构事理详解
Java 会走向晦暗吗?Kotlin 会取而代之吗
一次SQL优化的体验
关注「程序员小乐」,收看更多精彩内容嘿,你在看吗?