IOC是Inversion of Control的缩写,多数书籍翻译成“控制反转”,还有些书籍翻译成为“控制反向”或者“控制倒置”。
    1996年,Michael
Mattson在一篇有关探讨面向对象框架的文章中,首先提出了IOC 这个概念。对于面向对象设计及编程的基本思想,前面我们已经讲了很多了,不再赘述,简单来说就是把复杂系统分解成相互合作的对象,这些对象类通过封装以后,内部实现对外部是透明的,从而降低了解决问题的复杂度,而且可以灵活地被重用和扩展。IOC理论提出的观点大体是这样的:借助于“第三方”实现具有依赖关系的对象之间的解耦,如下图:

图1:IOC解耦过程

大家看到了吧,由于引进了中间位置的“第三方”,也就是IOC容器,使得A、B、C、D这4个对象没有了耦合关系,齿轮之间的传动全部依靠“第三方”了,全部对象的控制权全部上缴给“第三方”IOC容器,所以,IOC容器成了整个系统的关键核心,它起到了一种类似“粘合剂”的作用,把系统中的所有对象粘合在一起发挥作用,如果没有这个“粘合剂”,对象与对象之间会彼此失去联系,这就是有人把IOC容器比喻成“粘合剂”的由来。
 我们再来做个试验:把上图中间的IOC容器拿掉,然后再来看看这套系统:

图2:拿掉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的过程,由主动行为变为了被动行为,控制权颠倒过来了,这就是“控制反转”这个名称的由来。

依赖注入(Dependency
Injection
)   2004年,Martin
Fowler探讨了同一个问题,既然IOC是控制反转,那么到底是“哪些方面的控制被反转了呢?”,经过详细地分析和论证后,他得出了答案:“获得依赖对象的过程被反转了”。控制被反转之后,获得依赖对象的过程由自身管理变为了由IOC容器主动注入。于是,他给“控制反转”取了一个更合适的名字叫做“依赖注入(Dependency Injection)”。他的这个答案,实际上给出了实现IOC的方法:注入。所谓依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。

所以,依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情,就是指通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。
    我们举一个生活中的例子,来帮助理解依赖注入的过程。大家对USB接口和USB设备应该都很熟悉吧,USB为我们使用电脑提供了很大的方便,现在有很多的外部设备都支持USB接口。

图3:USB接口和USB设备

现在,我们利用电脑主机和USB接口来实现一个任务:从外部USB设备读取一个文件。
    电脑主机读取文件的时候,它一点也不会关心USB接口上连接的是什么外部设备,而且它确实也无须知道。它的任务就是读取USB接口,挂接的外部设备只要符合USB接口标准即可。所以,如果我给电脑主机连接上一个U盘,那么主机就从U盘上读取文件;如果我给电脑主机连接上一个外置硬盘,那么电脑主机就从外置硬盘上读取文件。挂接外部设备的权力由我作主,即控制权归我,至于USB接口挂接的是什么设备,电脑主机是决定不了,它只能被动的接受。电脑主机需要外部设备的时候,根本不用它告诉我,我就会主动帮它挂上它想要的外部设备,你看我的服务是多么的到位。这就是我们生活中常见的一个依赖注入的例子。在这个过程中,我就起到了IOC容器的作用。
    通过这个例子,依赖注入的思路已经非常清楚:当电脑主机读取文件的时候,我就把它所要依赖的外部设备,帮他挂接上。整个外部设备注入的过程和一个被依赖的对象在系统运行时被注入另外一个对象内部的过程完全一样。
 我们把依赖注入应用到软件系统中,再来描述一下这个过程:
    对象A依赖于对象B,当对象 A需要用到对象B的时候,IOC容器就会立即创建一个对象B送给对象A。IOC容器就是一个对象制造工厂,你需要什么,它会给你送去,你直接使用就行了,而再也不用去关心你所用的东西是如何制成的,也不用关心最后是怎么被销毁的,这一切全部由IOC容器包办。
    在传统的实现中,由程序内部代码来控制组件之间的关系。我们经常使用new关键字来实现两个组件之间关系的组合,这种实现方式会造成组件之间耦合。IOC很好地解决了该问题,它将实现组件间关系从程序内部提到外部容器,也就是说由容器在运行期将组件间的某种依赖关系动态注入组件中。

 IOC为我们带来了什么好处

我们还是从USB的例子说起,使用USB外部设备比使用内置硬盘,到底带来什么好处?
     第一、USB设备作为电脑主机的外部设备,在插入主机之前,与电脑主机没有任何的关系,只有被我们连接在一起之后,两者才发生联系,具有相关性。所以,无论两者中的任何一方出现什么的问题,都不会影响另一方的运行。这种特性体现在软件工程中,就是可维护性比较好,非常便于进行单元测试,便于调试程序和诊断故障。代码中的每一个Class都可以单独测试,彼此之间互不影响,只要保证自身的功能无误即可,这就是组件之间低耦合或者无耦合带来的好处。
     第二、USB设备和电脑主机的之间无关性,还带来了另外一个好处,生产USB设备的厂商和生产电脑主机的厂商完全可以是互不相干的人,各干各事,他们之间唯一需要遵守的就是USB接口标准。这种特性体现在软件开发过程中,好处可是太大了。每个开发团队的成员都只需要关心实现自身的业务逻辑,完全不用去关心其它的人工作进展,因为你的任务跟别人没有任何关系,你的任务可以单独测试,你的任务也不用依赖于别人的组件,再也不用扯不清责任了。所以,在一个大中型项目中,团队成员分工明确、责任明晰,很容易将一个大的任务划分为细小的任务,开发效率和产品质量必将得到大幅度的提高。
     第三、同一个USB外部设备可以插接到任何支持USB的设备,可以插接到电脑主机,也可以插接到DV机,USB外部设备可以被反复利用。在软件工程中,这种特性就是可复用性好,我们可以把具有普遍性的常用组件独立出来,反复利用到项目中的其它部分,或者是其它项目,当然这也是面向对象的基本特征。显然,IOC不仅更好地贯彻了这个原则,提高了模块的可复用性。符合接口标准的实现,都可以插接到支持此标准的模块中。
     第四、同USB外部设备一样,模块具有热插拔特性。IOC生成对象的方式转为外置方式,也就是把对象生成放在配置文件里进行定义,这样,当我们更换一个实现子类将会变得很简单,只要修改配置文件就可以了,完全具有热插拨的特性。
 以上几点好处,难道还不足以打动我们,让我们在项目开发过程中使用IOC框架吗?

IOC容器的技术剖析
    IOC中最基本的技术就是“反射(Reflection)”编程,目前.Net C#、Java和PHP5等语言均支持,其中PHP5的技术书籍中,有时候也被翻译成“映射”。有关反射的概念和用法,大家应该都很清楚,通俗来讲就是根据给出的类名(字符串方式)来动态地生成对象。这种编程方式可以让对象在生成时才决定到底是哪一种对象。反射的应用是很广泛的,很多的成熟的框架,比如象Java中的Hibernate、Spring框架,.Net中 NHibernate、Spring.Net框架都是把“反射”做为最基本的技术手段。
    反射技术其实很早就出现了,但一直被忽略,没有被进一步的利用。当时的反射编程方式相对于正常的对象生成方式要慢至少得10倍。现在的反射技术经过改良优化,已经非常成熟,反射方式生成对象和通常对象生成方式,速度已经相差不大了,大约为1-2倍的差距。
    我们可以把IOC容器的工作模式看做是工厂模式的升华,可以把IOC容器看作是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,然后利用编程语言的的反射编程,根据配置文件中给出的类名生成相应的对象。从实现来看,IOC是把以前在工厂方法里写死的对象生成代码,改变为由配置文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。

下面我们来看一个使用轻量级的IoC架构---StructureMap 的例子

using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using StructureMap;

namespace ConsoleApplication1
 {
     class Program
     {
         private static void
Main(string[] args)
         {
             ConfigureDependencies();

IAppEngine
appEngine = ObjectFactory.GetInstance<IAppEngine>();
             appEngine.Run();
         }

private static
void ConfigureDependencies()
         {
            
StructureMapConfiguration.ForRequestedType<IAppEngine>().TheDefaultIsConcreteType<AppEngine>();
            
StructureMapConfiguration.ForRequestedType<IGreeter>().TheDefaultIsConcreteType<EnglishGreeter>();
            
StructureMapConfiguration.ForRequestedType<IOutputDisplay>().TheDefaultIsConcreteType<ConsoleOutputDisplay>();
         }
     }

public class
AppEngine : IAppEngine
     {
         private readonly IGreeter greeter;
         private readonly IOutputDisplay
outputDisplay;

public
AppEngine(IGreeter greeter, IOutputDisplay outputDisplay)
         {
             this.greeter = greeter;
             this.outputDisplay = outputDisplay;
         }

public void
Run()
         {
            
outputDisplay.Show(greeter.GetGreeting());
         }
     }

public interface
IAppEngine
     {
         void Run();
     }

public interface
IGreeter
     {
         string GetGreeting();
     }

public class
EnglishGreeter : IGreeter
     {
         public string GetGreeting()
         {
             return "Hello";
         }
     }

public class
FrenchGreeter : IGreeter
     {
         public string GetGreeting()
         {
             return "Bonjour";
         }
     }

public interface
IOutputDisplay
     {
         void Show(string message);
     }

public class
ConsoleOutputDisplay : IOutputDisplay
     {
         public void Show(string message)
         {
             Console.WriteLine(message);
         }
     }
 }

IOC控制反转的更多相关文章

  1. 回顾Spirng ioc 控制反转

    Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的.结合网上对Spring Ioc的理解,回顾一下自 ...

  2. 谈谈php里的IOC控制反转,DI依赖注入

    理论 发现问题 在深入细节之前,需要确保我们理解"IOC控制反转"和"DI依赖注入"是什么,能够解决什么问题,这些在维基百科中有非常清晰的说明. 控制反转(In ...

  3. DI依赖注入/IOC控制反转

    DI依赖注入# 啥都不说,直接上代码 <?php class UserController { private $user; function __construct(UserModel $us ...

  4. IoC实践--用Autofac实现MVC5.0的IoC控制反转方法

    Autofac是一个.net平台下发性能还不错的IoC框架,利用它可以实现依赖注入和控制反转,使自己的软件模块之间的耦合性大大降低,让软件扩展.维护更加容易.控制反转(Inversion of Con ...

  5. IoC控制反转与DI依赖注入

    IoC控制反转与DI依赖注入 IoC: Inversion of Control IoC是一种模式.目的是达到程序的复用.下面的两篇论文是对IoC的权威解释: InversionOfControl h ...

  6. Spring学习之Ioc控制反转(1)

    开始之前: 1. 本博文为原创,转载请注明出处 2. 作者非计算机科班出身,如有错误,请多指正 ---------------------------------------------------- ...

  7. Spring学习之Ioc控制反转(2)

    开始之前: 1. 本博文为原创,转载请注明出处 2. 作者非计算机科班出身,如有错误,请多指正 ---------------------------------------------------- ...

  8. Spring框架之IOC(控制反转)

    [TOC] 第一章Spring框架简介 IOC(控制反转)和AOP(面向方面编程)作为Spring框架的两个核心,很好地实现了解耦合.所以,简单来说,Spring是一个轻量级的控制反转(IoC)和面向 ...

  9. Spring详解(二)------IOC控制反转

    我相信提到 Spring,很多人会脱口而出IOC(控制反转).DI(依赖注入).AOP等等概念,这些概念也是面试官经常问到的知识点.那么这篇博客我们就来详细的讲解 IOC控制反转. ps:本篇博客源码 ...

  10. IOC 控制反转(Inversion of Control,英文缩写为IoC)

    在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑. 在这样的齿轮组中,因为是协同工作,如果有一个齿轮出了问题,就可能会影响到整个齿 ...

随机推荐

  1. 我的第一段ionic代码

    ionic是基于angularjs的前端框架,用于实现移动app. 下面是第一段代码,先贴代码,有时间再整理: demo1.htm <!DOCTYPE html> <html ng- ...

  2. java中循环控制结构

    1. break结束break所在循环 for(i……) { for(j……) { break;  //结束循环j } } 2.带标签的break. java中的标签只用在循环语句前面. outer: ...

  3. PHP 杂项函数

    PHP 杂项 函数 PHP 杂项函数简介 我们把不属于其他类别的函数归纳到杂项函数类别. 安装 杂项函数是 PHP 核心的组成部分.无需安装即可使用这些函数. Runtime 配置 杂项函数的行为受 ...

  4. Box layout

    Layout management with layout classes is much more flexible and practical. It is the preferred way t ...

  5. volist 自增序号 分页如何实现?

    TP框架模板中如何生成自增数据 {$_GET['p']*10-10+$i} /* 分页序号计算    */ function addnum($k,$num){     return ($k +1 ) ...

  6. Java之逆向工程(1) - 反编译、修补和逆向工程技术 读书笔记

    透视JAVA——反编译.修补和逆向工程技术 读书笔记 1.  Java source is not compiled to binary machine code like C/C++ source ...

  7. Java之字节码(1) - 深入解析

    转载地址 一:Java字节代码的组织形式 类文件{ OxCAFEBABE,小版本号,大版本号,常量池大小,常量池数组,访问控制标记,当前类信息,父类信息,实现的接口个数,实现的接口信息数组,域个数,域 ...

  8. jQuery获取select中全部option值

    <select id="language"> <option value="">请选择</option> <optio ...

  9. 局域网Ubuntu与WinXP实现文件共享

    时间:2008-11-28 11:27:55   从新立得软件包管理器中安装Samba和Smbfs.Samba是在Unix系统中用于共享文件和打印机的应用软件.Smbfs is a filesyste ...

  10. 常见URL字符及URL编码值

    大家上网的时候一定会看到很多这类情况有的网页地址都是%22%32%11%23%21等这种机器语言恐怕只有机器能马上辨认吧现在我把大概知道的总结一下 字符                         ...