看《墨攻》理解IoC
???? IoC(反向控制:Inverse of Control)是Spring容器的底层核心功能,AOP功能、声明事务等功能在此基础上生根开花。但是IoC这个重要的概念却比较晦涩隐讳,拐弯抹角,不容易让人望文生义,不能不说是一大遗憾。不过IoC确实包括很多内涵,它涉及到代码解耦,设计模式优化等问题的考量。
????? 2006年多部贺岁大片以让人应接不暇的频率纷至沓来,其中张之亮的《墨攻》算是比较出彩的一部,讲述了战国时期墨家人革离帮助梁国反抗赵国侵略的个人英雄主义故事,恢宏壮阔,浑雄凝重的历史场面相当震撼。其中有一个场景:当刘德华所饰的墨者革离到达梁国都城下,城上梁国守军问:“来者何人?”,刘德华回答:“墨者革离!”,我们不妨用Java对这段“城门问对”的场景进行编剧并借由这个例子来理解IoC的内涵。
???? 剧本和饰演者耦合
???? MoAttack代表《墨攻》的剧本,cityGetAsk()代表“城门问对”这段剧情,LiuDeHua是具体饰演者刘天王:
图 1 剧本和演员直接耦合
????? 一个明智的编剧在剧情创作时应围绕故事的角色进行,而不应考虑角色的具体饰演者,这样才可能在剧本投拍时自由地遴选任何适合的演员,而非绑定在刘德华一人身上。通过以上的分析,我们知道需要为该剧本主人公革离定义一个接口,以角色进行剧情安排,饰演者实现角色的接口:?
?
????? 我们希望剧本和演员无关,可是,在图2中,我们看到MoAttack同时依赖于GeLi接口和LiuDeHua类,并没有达到我们所期望的剧本仅依赖于角色的目的。可是角色最终又必须通过具体的演员才能完成拍摄,如何将让LiuDeHua和剧本无关而又能完成GeLi的具体动作呢?当然是在影片投拍时,导演将LiuDeHua安排在GeLi的角色上,通过导演之手将剧本、角色、饰演者装配起来。
图 3 剧本和饰演者解耦了
????? 通过引入导演,剧本和具体的饰演者解耦了,对应到软件中,导演象是一个装配器,将具体的饰演者赋给了剧本的角色。
现在我们可以反过来讲解IoC的概念了。IoC(Inverse of Control)的字面意思是控制反转,它包括两个层面的内容:其一是“控制”,其二是“反转”,到底是什么东西的控制被反转了呢?对应到前面的例子, “控制”是指GeLi角色扮演者的选择控制权,“反转”是指这种选择控制权从《墨攻》剧本中移除,转交到导演的手中。对于程序来说,即是某一接口具体实现类的选择控制权从客户类中移除,转交给第三方来确定,客户类不知道是哪个具体的实现类,它通过接口方法对实现类进行调用。
????? 因为IoC确实不够开门见山,因此业界曾进行了广泛的讨论,最终软件界的泰斗级人物Martin Fowler提出了DI(依赖注入:Dependency Injection)的概念,即将客户类对接口实现类的依赖关系由第三方(容器或协作类)注入,以移除客户类对具体接口实现类的依赖。“依赖注入”的概念显然比“控制反转”直接达意,易于理解。
IoC的三种类型
????? 从注入方法上看,主要可以划分为三种的注入类型,分别是构造函数注入、属性注入和接口注入,Spring支持构造函数注入和属性注入。下面我们继续使用以上的例子说明这三种注入方法的区别。
1、构造函数注入
??? 我们通过客户类的构造函数,将接口实现类通过接口变量传入,如代码清单 3 3所示:?
???? 通过new XmlBeanFactory(“beans.xml”)等方式即可启动容器,在容器启动时,Spring根据配置文件的描述信息,通过Java的反射机制自动实例化Bean并完成依赖关系的建立,从容器中即可返回准备就绪的Bean实例,以待后续的使用。
小结:
????? 随着Spring的广泛应用,IoC的概念被越来越多的提及,可是很多说者因为IoC本身的晦涩往往并不清楚其中的意义,我们通过时下叫座的贺岁大片《墨攻》来解释IoC的概念,相信对加深IoC概念的理解有所补益。?
