认识IoC

  第一次接触IoC是我在学习MVP框架的时候,搭建一个MVP框架需要用到IoC,那时候就以为IoC就是依赖注入,但在后来的逐步了解中发现那个只是它的别名而已。IoC全称应该是Inversion
of Control,中文称为控制反转;而依赖注入的简称是DI,全称是Dependency
Injection,个人觉得这两者也不是那么一个别名的关系而已,控制反转给我的感觉更多的是一种思想,而依赖注入却正好是一种实现方式。那这里说说概念

  • 控制反转:应用本身不负责以来对象的维护和创建,而交给一个外部容器来负责。这样控制权就由应用转到了外部IoC容器,控制权就实现了所谓的反转。

  • 依赖注入:由外部容器在运行时动态地将以来的对象注入到组件中。

以上概念摘自蒋老师的著作《ASP.NET MVC4
框架揭秘》。但是技术这东西又没必要向理论学术那样严谨,能让人知晓其中意图则可,最初UML最初创作处理也是为了达到这个目的。

  高内聚低耦合一直是软件开发中不断追求的,现在各种框架MVC,MVP等都是为了解耦而诞生的。在我阅读微软的开源项目PetShop时发现里面用了耳熟能详的三层架构中使用了最初我学C#时不知有什么作用的一个东西——接口Interface。它的存在很大的目的就是为了解耦,它能使一些比较具体的事物抽象化。那么本篇所讨论的IoC也是使用了接口。

目前有很多IoC框架:Unity,Spring.NeT,Ninject,StructureMap等。Ninject在我实践MVP的时候用过,Unity在我阅读蒋老师的著作时了解过,那么这回我将会尝试一下之前没用过的Unity,体验一下依赖注入。

模拟使用一个三层架构来体验这个Unity

定义DAL,BLL,UI层的接口IDAL,IBLL,IUI以及实现它们的类DAL,BLL,UI。


 1     interface IDAL
2 {
3 DataTable QueryDatas();
4 }
5 interface IBLL
6 {
7 List<object> GetSomeDatas();
8 }
9
10 interface IUI
11 {
12 void ShowData(IBLL bll);
13 }
14
15 class DAL : IDAL
16 {
17
18 public DataTable QueryDatas()
19 {
20 DataTable table = new DataTable();
21 table.Columns.Add("Col");
22 for (int i = 0; i < 10; i++)
23 {
24 table.Rows.Add(i);
25 }
26 return table;
27 }
28 }
29 class BLL : IBLL
30 {
31 [Dependency]
32 public IDAL dal { get; set; }
33
34 public List<object> GetSomeDatas()
35 {
36 List<object> result = new List<object>();
37 DataTable table = dal.QueryDatas();
38 foreach (DataRow row in table.Rows)
39 {
40 result.Add(row[0]);
41 }
42 return result;
43 }
44 }
45 class UI : IUI
46 {
47 [InjectionMethod]
48 public void ShowData(IBLL bll)
49 {
50 List<object> datas = bll.GetSomeDatas();
51 foreach (object item in datas)
52 {
53 Console.WriteLine(item);
54 }
55 }
56 }

在上面的代码中BLL类的dal属性使用了[Dependency]
Attribute,使得该属性是通过IoC容器自动去赋值,不需要通过代码给它显示赋值。UI的ShowData方法用了[InjectionMethod]
Attribute,该方法在UI类被IoC容器自动执行。实际上上面代码设计到IoC里面三种方式的其中两种属性注入和接口(方法)注入,那么还剩下一种就是构造器注入,

  • 在上面使用了Dependency 
    Attribute的IDAL属性则是使用属性注入,使用了依赖注入的属性在IoC容器构造对象的时候自动初始化赋值;

  • 上面使用了InjectionMethod
    Attribute的ShowData方法则是使用接口(方法)注入,使用了依赖注入的方法在IoC容器构造对象的时候自动执行该方法;

  • 还有一种没有列举出来的就是构造器注入
    IoC容器会自动选择和调用合适的构造函数以创建依赖的对象。如果被选择的构造函数是带参数的,IoC容器是会去创建该参数的实例的。上面的代码还没可以执行,需要在配置文件中添加以下内容


 1 <configuration>
2 <configSections>
3 <section name="unity"
4 type="
5 Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
6 Microsoft.Practices.Unity.Configuration"/>
7 </configSections>
8 <unity>
9 <containers>
10 <container name="defaultContainer">
11 <register type="AllTypeTestControl.IDAL,AllTypeTestControl" mapTo="AllTypeTestControl.DAL,AllTypeTestControl"/>
12 <register type="AllTypeTestControl.IBLL,AllTypeTestControl" mapTo="AllTypeTestControl.BLL,AllTypeTestControl"/>
13 <register type="AllTypeTestControl.IUI,AllTypeTestControl" mapTo="AllTypeTestControl.UI,AllTypeTestControl"/>
14 </container>
15 </containers>
16 </unity>
17 </configuration>

上面这段内容是指定了给Unity的IoC容器各个接口与实现类的映射关系,AllTypeTestControl.IDAL类型映射到AllTypeTestControl.DAL中去,表示通过DAL来实现IDAL的注入,其他同理。但每一项的注册要按照


<register type="接口全名,程序集名" mapTo="类全名,程序集名"/> 

通过下面的测试代码来测试


1         public static void TestMain()
2 {
3 IUnityContainer container = new UnityContainer();
4 UnityConfigurationSection configuration =
5 ConfigurationManager.GetSection(UnityConfigurationSection.SectionName)
6 as UnityConfigurationSection;
7 configuration.Configure(container, "defaultContainer");
8 UI ui = container.Resolve<IUI>() as UI ;
9 }

主要是构造了一个IoC的容器,然后载入了配置文件的映射信息,除了通过配置文件来确定映射关系外,还可以通过代码的形式来确定


        public static void TestMain()
{
IUnityContainer container = new UnityContainer();
container.RegisterType<IDAL, DAL>();
container.RegisterType<IBLL, BLL>();
container.RegisterType<IUI, UI>();
UI ui = container.Resolve<IUI>() as UI ;
}

代码的运行结果如下

现在则把上面的BLL作一下修改


 1     class BLL : IBLL
2 {
3 //[Dependency]
4 //public IDAL dal { get; set; }
5
6 private IDAL dal;
7
8 //[InjectionConstructor]
9 public BLL(IDAL dal)
10 {
11 this.dal = dal;
12 }
13
14 //[InjectionConstructor]
15 public BLL()
16 {
17
18 }
19
20 public List<object> GetSomeDatas()
21 {
22 List<object> result = new List<object>();
23 DataTable table = dal.QueryDatas();
24 foreach (DataRow row in table.Rows)
25 {
26 result.Add(row[0]);
27 }
28 return result;
29 }
30 }

结果仍然和上面的一样,IoC容器仍然能正确的匹配出类型构造了DAL对象。那么如果给BLL()构造函数加了InjectionConstructor
Attribute,IoC容器只会去匹对带了InjectionConstructor Attribute的构造函数,这样BLL(IDAL
dal)构造函数则不会被调用,运行起来就会抛出空引用异常。假如给BLL(IDAL dal)也加上了InjectionConstructor
Attribute,那么它与无参构造函数BLL()属于同级,IoC则会也调用BLL(IDAL dal)构造函数,dal字段能被正常的赋值。

  通过上面的实践中能感觉到IoC有GOF中的工厂模式思想。用户在使用着一个对象,但它并不负责对象的构造,把对象的构造移交了给第三方,在IoC中就是IoC容器,在工厂方法里面则是工厂了。在ASP.NET
MVC中也使用了IoC,迷你MVC框架中控制器的构造是通过了一个工厂利用反射机制来构造出来的,而实际的ASP.NET MVC则是使用了IoC。

  对IoC的了解还不算多,手上有一份Ninject的源码,但一直没看,现在工作忙了,连博客也少写了,时间得好好分配,要保持学习。以上有什么说的不对的请指正,有什么好的建议或意见也请分享,谢谢!

时间: 2024-10-13 02:21:21

认识IoC的相关文章

框架学习之Spring(一IOC)----HelloWrod

一.概述 Spring是一个开源框架,它的核心是控制反转(IOC)和面向切面(AOP).简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式)轻量级开源框架. EE 开发分成三层结构: * WEB 层:Spring MVC. * 业务层:Bean 管理:(IOC) * 持久层:Spring 的 JDBC 模板.ORM 模板用于整合其他的持久层框 架 注:Spring框架既可以单独使用 ,也可以结合其他优秀框架一起使用. 二.环境搭建 开发包: 下载地址:http://

分享基于.NET MVC+EF CodeFirst+IOC+EasyUI的框架设计

**注:要做工,没什么时间,等有空时会上传到GIT,项目结构如上,简单的说一下: **支持IOC及多数据库等,各项目由MVC区域隔离: 主要使用基于接口与抽象类进行高度的抽象与接口隔离,与其它框架比较优点如下: 1,抽象度非常高,接口隔离,项目清晰完整,任何一部分均可且容易替换:一开始就非常注重非陷入复杂化: 2,框架非常易用,且易于扩展:编程新手也可立即上手使用: 3,设计目标为:轻量化.高抽象度.可扩展性.模块任意替换.清晰简洁易用(易懂.代码量要少[没必要码农]): **NetDevelo

iOS控制反转(IoC)与依赖注入(DI)的实现

背景 最近接触了一段时间的SpringMVC,对其控制反转(IoC)和依赖注入(DI)印象深刻,此后便一直在思考如何使用OC语言较好的实现这两个功能.Java语言自带的注解特性为IoC和DI带来了极大的方便,要在OC上较好的实现这两个功能,需要一些小小的技巧. 控制反转和依赖注入 控制反转 简单来说,将一个类对象的创建由手动new方式改为从IOC容器内获取,就是一种控制反转,例如我们现在要创建一个ClassA类,则常规方法为 ClassA *a = [ClassA new]; 如果使用控制反转,

Atitit.ioc&#160;动态配置文件guice&#160;设计原理

Atitit.ioc 动态配置文件guice 设计原理 1. Bat启动时注入配置文件1 2. ioc调用1 3. Ioc 分发器 配合 apche  MethodUtils.invokeStaticMethod2 1. Bat启动时注入配置文件 SET JAVA_HOME=C:\Program Files\Java\jdk1.8.0_71 set  RESIN-HOME=c:\resin-4.0.22 set classpath=%classpath%;%RESIN-HOME%\lib\jas

Spring IoC/DI

前言 假设项目层次划分包括logic层和dao层,logic层调用dao层完成业务逻辑,dao层一般与数据库交互.定义两个组件,TestLogic和TestDao,分别操作接口ILogic和IDao,这样程序开发时需要考虑怎样管理这两个组件. 传统方式 这种方式中,当TestLogic组件需要调用TestDao组件时,直接使用关键字new IDao testDao = new TestDao(); 这种方式简单直观,但造成了对外部组件的严重依赖,程序高度耦合,效率低下.当项目需要更换组件时需要修

Spring技术内幕——Spring Framework的IOC容器实现(二)

三.IOC容器的初始化过程 IOC容器的初始化时由前面介绍的refresh方法来启动的,这个方法标志着IOC容器的正式启动.这个启动包括BeanDefinition的Resource定位.载入和注册.下面我们将详细分析这三个实现过程,Spring把这三个过程分开,并使用不同的模块来完成,通过这样的设计让用户更加灵活的这三个过程进行剪裁和扩展,定义出最适合自己的IOC容器的初始化过程. 第一个过程: Resource定位过程,是指BeanDefinition的资源定位,他由ResourceLoad

手把手教你实现Spring ioc

手把手教你实现Spring ioc "Don't call us, we'll call you(不要联系我,我会主动联系你)" 这是好莱坞很经典的一句话,应用在ioc(控制反转)领域,发现理解起来相得益彰--你作为用户不需要控制业务实体的生成,交给我容器来控制,这就是控制反转.不过,这样理解起来也有点麻烦,套用面向对象大师Martin Fowler的说法更为贴切: "Dependency Inversion(依赖注入)" 当容器中所有的实体bean 都被管理起来的

好记性不如烂笔头83-spring3学习(4)-spring的BeanFactory(IoC容器)

我们一般把BeanFactory叫做IoC容器,叫ApplicationContext 为应用上下文(或者Spring容器) BeanFactory是spring框架的核心,实现依赖注入[使个组件的依赖关系从代码中独立出来,使用配置文件即可实现这种依赖关系]和bean声明周期的管理 . BeanFactory[IoC容器]启动过程:分为两个阶段,一个是容器启动阶段,另外一个是Bean实例化阶段 容器启动阶段:加载配置 -–> 分析配置信息 -–>装备到BeanDefinition -–>

Spring笔记(二):Ioc 之注入与装配

一.Spring依赖注入的原理 二.依赖注入的实现 (一)对象的注入 1.简单属性注入 1)源代码 package main.java.com.spring.ioc.base.dao.impl; import main.java.com.spring.ioc.base.dao.PersonDao; /** * * PersonDiDaoImpl * @title * @desc * @author SAM-SHO * @Dec 28, 2014 */ public class PersonDiD

浅谈Spring(二)IOC原理

一.引言 我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑.举例:如果我们打开机械式手表的后盖,就会发现其是由N个齿轮组成,各个齿轮分别带动时针.分针和秒针顺时针旋转,从而在表盘上产生正确的时间.在这样的齿轮组中,如果有一个齿轮出了问题,就可能会影响到整个齿轮组的正常运转.齿轮组中齿轮之间的啮合关系,与软件系统中对象之间的耦合关系非常相似.对象之间的耦合关系是无法避免的,也是必要的,这是协同工作的基础.现在,伴随着