首页 > 技术文章 > C#基础知识之IOC

qtiger 2019-07-12 16:03 原文

上篇文章介绍了依赖注入,这里接着梳理下IOC。

一、IOC思想

IOC(Inversion of Control),即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,IOC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下: 

  • 谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IOC是有专门一个容器来创建这些对象,即由IOC容器来控制对象的创建;谁控制谁?当然是IOC容器控制了对象;控制什么?那就是主要控制了外部资源获取
  • 为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。

用图例说明一下,传统程序设计(即正转)如下图,都是主动去创建相关对象然后再组合起来:

 

 

  

当有了IoC/DI的容器后,在客户端类中不再主动去创建这些对象了,如下图:

 

二、IOC能做什么

IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;利用IOC思想去设计一个IoC容器,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。

其实IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC容器来创建并注入它所需要的资源了。IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”;即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。 总结来说IOC思想要完成的功能:

  1. 负责对象的创建
  2. 负责对象的注入,即在需要的地方提供需要的对象

三、IOC和DI

上边说道IOC思想,那么IOC和DI的关系是什么呢?

因为IOC概念比较模糊,是一种思想上的指导,可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系。于是Martin Fowler在2004年引入了一个新的名称,即依赖注入。但是IOC和ID还是有本质区别的,控制反转是一种思想,而依赖注入是一种软件设计模式,是一种在类及其依赖项之间实现控制反转的技术。理论上讲,IOC思想的落地除了DI这种实现方式外,还有其他的实现形式。但是DI过于主流,导致IOC和DI混淆了。在实际开发过程中,基本都是通过DI的设计模式实现了IOC思想。

四、IOC、DI和反射

上边介绍了IOC的思想,总结来说两个功能:

  1. 负责对象的创建
  2. 负责对象的注入,即在需要的地方提供需要的对象

上边还介绍了IOC和DI的关系,即DI可以认为是IOC思想比较主流的一个实现方式。那么针对于IOC负责的两个功能,ID设计模式是如何实现的呢?

  1. 对象的创建:即对象的初始化统一处理,放到IOC容器中,统一管理。
  2. 对象的注入:上文曾经讨论了三种对象注入方式,分别是setter注入、构造函数注入和依赖获取。 

IOC是一种思想,DI是对该思想的实现,在实现过程中,利用反射的原理,解决了很多问题,比如利用反射原理避免了破坏OCP原则,总体来讲反射可以认为是DI实现的核心技术。

五、IOC容器

1、IOC容器的概念

前边提到IOC容器,那么到底什么是IoC容器?我们还是先来看看它的出现背景。

我们知道,软件开发领域有句著名的论断:不要重复发明轮子!因为软件开发讲求复用,所以,对于应用频繁的需求,总是有人设计各种通用框架和类库以减轻人们的开发负担。例如,数据持久化是非常频繁的需求,于是各种ORM框架应运而生;再如,对MVC的需求催生了Struts等一批用来实现MVC的框架。
随着面向对象分析与设计的发展和成熟,OOA&D被越来越广泛应用于各种项目中,然而,我们知道,用OO就不可能不用多态性,用多态性就不可能不用依赖注入,所以,依赖注入变成了非常频繁的需求,而如果全部手工完成,不但负担太重,而且还容易出错。再加上反射机制的发明,于是,自然有人开始设计开发各种用于控制反转的专用框架。这些专门用于控制反转的组件或框架,就是IoC Container。
从这点看,IoC Container的出现有其历史必然性。目前,最著名的IoC也许就是Java平台上的Spring框架的IoC组件,而.NET平台上也有Spring.NET和Unity等。

2、IOC Container的分类

因为现在IoC Container都设计很完善,几乎支持所有依赖注入方式。不过,根据不同框架的特性和惯用法,还是可以讲IoC Container分为两个大类。

(1)重量级IOC Container

所谓重量级IoC Container,是指一般用外部配置文件(一般是XML)作为依赖源,并托管整个系统各个类的实例化的IoC Container。这种IoC Container,一般是承接了整个系统几乎所有多态性的依赖注入工作,并承接了所有服务类的实例化工作,而且这些实例化依赖于一个外部配置文件,这种IoC Container,很像通过一个文件,定义整个系统多态结构,视野宏大,想要很好驾驭这种IoC Container,需要一定的架构设计能力和丰富的实践经验。

Spring和Spring.NET是重量级IoC Container的例子。一般来说,这种IoC Container稳定性有余而活性不足,适合进行低活多态性的依赖注入。

(2)轻量级IoC Container

还有一种IoC Container,一般不依赖外部配置文件,而主要使用传参的Setter或Construtor注入,这种IoC Container叫做轻量级IoC Container。这种框架很灵活,使用方便,但往往不稳定,而且依赖点都是程序中的字符串参数,所以,不适合需要大规模替换和相对稳定的低活多态性,而对于高活多态性,有很好的效果。

Unity是一个典型的轻量级IoC Container。

(3)NET平台上典型IoC Container推介

  • Spring.NET 

Spring.NET是Java平台上Spring对.NET平台的移植,使用方法和Spring很像,并且功能强大,是.NET平台上大中型开发IoC Container的首选之一。除了DI外,Spring.NET也包括AOP等诸多功能。Spring.NET的官方网站是:http://www.springframework.net/

  • Unity 

对于小型项目和讲求敏捷的团队,Spring.NET可能有点太重量级,那么可以选择轻量级的Unity。Unity是微软patterns & practices团队推出的轻量级框架,非常好用,目前最新版本是1.2。Unity的官方网站是:http://unity.codeplex.com/ 

 

 

推荐阅读