Ioc的实现及应用

来源:互联网 发布:软件巡检方案 编辑:程序博客网 时间:2024/04/29 22:19

什么是Ioc

什么是Ioc(Inversion of control),Ioc又叫DI(Dependency Injection),就是将你设计的类交给系统来控制,而不是你自己编码控制,这个应该是来源于java中的。做过j2ee开发的朋友肯定熟悉struts+hibernate+spring的结构。而spring正是为了实现Ioc而存在的,可想而知Ioc是多重要。当然我们不是在谈java而是在说.net,因为Ioc是一种思想而不是针对某种语言的。在.net中我们也是会经常碰到Ioc的,做.net开发的朋友肯定知道sprint.net、Castle等,这些都是优秀的Ioc框架。那么Ioc是做什么用的呢?

优缺点

IoC最大的好处是什么?因为把对象生成放在了XML里定义,所以当我们需要换一个实现子类将会变成很简单(一般这样的对象都是实现于某种接口的),只要修改XML就可以了,这样我们甚至可以实现对象的热插拔(有点象USB接口和SCSI硬盘了)。
IoC最大的缺点是什么?(1)生成一个对象的步骤变复杂了(事实上操作上还是挺简单的),对于不习惯这种方式的人,会觉得有些别扭和不直观。(2)对象生成因为是使用反射编程,在效率上有些损耗。但相对于IoC提高的维护性和灵活性来说,这点损耗是微不足道的,除非某对象的生成对效率要求特别高。(3)缺少IDE重构操作的支持,如果在Eclipse要对类改名,那么你还需要去XML文件里手工去改了,这似乎是所有XML方式的缺憾所在。


Ioc的作用

    Jon Tirsén 与 Aslak Hellesøy(PicoContainer的两位开发者)在2003年Java Polis的演讲经常被人们拿来讨论Ioc,其中的Kiss实例是人们说的最多的,这里举个和它类似的例子。


先看一下上图,如果现在我需要一个蛋糕,现在有几种方式可以实现。第一就是自己动手来做,第二就是我有朋友他做的比较好我拜托他帮我做,第三种就是我直接打电话给蛋糕房送货上门。刚好这三种方式也是我们设计三层架构时实现层间解耦方式的演变,我在图的下方已经标出来。三层架构中虽然我们在BLL调用DAL的时候(UI调用BLL也是如此)不是直接通过new来直接实例化的,但是在DALFactory和BLLFactory的内部还是是直接new一个对应实例来创建对象的,相当于自己没有直接做而是委托别人来做,但是有了Ioc之后工厂也就不需要那么麻烦了,可以直接拿现成了。 或许你还有些模糊,不过没关系,接着往下看,我们再具体些,看看下面这两幅图:


    比较一下这两幅图有什么异同点。这两幅图大部分都是相同的,不同点就是DALFactory和DAL之间不再耦合了,BLLFactory和BLL之间也不再耦合了,也就是说工厂和对应的层之间的耦合性降低了,当然了,这一切归功于Ioc。

    “抽象”的概念是非常重要的,但是不管怎么样抽象,到了最后还是需要具体实现。我们理想的状况就是具体对象的创建永远都不要出现在代码中,也就是说我们不要出现内部依赖,那怎么办呢?当然就是将内部依赖转移到外部依赖中去。依赖虽然是必须的,但是一旦将依赖由内部转移到外部就可以将该依赖注入到模块中,因此也叫“依赖注入”。

    如果按照上面第二幅图的做法,我们在工厂内部就不需要直接通过new来创建对应的实例了,而只需要通过一个字符串类型的名称从Ioc容器中获得然后转化为对应的接口类型就可以了。

自己实现Ioc

    说了那么多Ioc的优点,不如我们自己实现一个Ioc来对它彻底的认识。我们通过创建一个IocContainer来管理我们的DAL和BLL中的类,由于IocContainer在项目中需要大量使用,为了节省开销我们采用单例模式。我们在IocContainer的构造函数中读取xml文件(我们将DAL及BLL中的类的信息写到xml文件中,这样方便我们管理)然后利用反射实例化所有的类,接着将这些实例放到IDicrectory中,为了方便我们找到这些实例,我们建立一个索引器。这样一来我们在工厂中就不需要通过new来创建这些类了,而是直接到我们的容器中直接去取,这样工厂也不再和对应的层耦合了。好了,道理比较简单,就是利用反射原理(其实对于像Sprint.net和Castle这样的框架也是如此)直接来看源代码吧(我们仍然以登录为例,其他代码跟另外一篇博客“传统三层架构”中完全相同就不再贴出来):

先看看配置文件IocContainer.xml:


    <?xml version="1.0" encoding="utf-8" ?>      <Container assemblyName="UI">        <Class namespace="UI.DAL" name="UserAccess"></Class>        <Class namespace="UI.BLL" name="UserLogic"></Class>      </Container>  



再看看IocContainer.cs:

    using System;      using System.Collections.Generic;      using System.Linq;      using System.Text;      using System.Xml;      using System.Reflection;      namespace UI      {          class IocContainer          {              private static IocContainer contaner;              private static object obj = new object();              private IDictionary<string, object> instances;              private IocContainer()              {                  instances = new Dictionary<string, object>();                  XmlDocument xmlDoc = new XmlDocument();                  xmlDoc.Load("IocContainer.xml");                  XmlNodeList xmlNodes= xmlDoc.SelectNodes("Container/Class");                  string assemblyName = xmlDoc.SelectSingleNode("Container").Attributes["assemblyName"].Value;                  foreach (XmlNode node in xmlNodes)                  {                      XmlAttributeCollection xmlAttributes = node.Attributes;                      string nameSpace = string.Empty;                      string className = string.Empty ;                      nameSpace = xmlAttributes["namespace"].Value;                      className = xmlAttributes["name"].Value;                      object myObject = Assembly.Load(assemblyName).CreateInstance(nameSpace+"."+className);                      instances.Add(className, myObject);                  }              }              public static IocContainer CreateInstance()              {                  lock (obj)                  {                      if (contaner == null)                      {                          contaner = new IocContainer();                      }                  }                  return contaner;              }              //构造索引器              public object this[string str]              {                  get                  {                      return instances[str];                                    }              }          }      }  




好了,看看如何使用,以DALFactory为例(BLLFactory一样),这也是我们进行解耦的核心(上面那些是为这一步打基础),我们的面向接口编程通过下面的代码就可以完全反映出来,就从我们在下面的代码中没有看到UserAccess就可说明DALFactory已经不再依靠DAL了,他们之间已经没有耦合性了:

    using System;      using System.Collections.Generic;      using System.Linq;      using System.Text;      using UI.IDAL;      using UI.DAL;      namespace UI.DALFactory      {          class UserAccessFactory          {              public static IUserAccess CreateUserAccess()              {                  return (IUserAccess)IocContainer.CreateInstance()["UserAccess"];              }          }      }  


 

主要代码就上面这些,道理在上面也已经说的很明白了。为了方便查看将源代码提供给大家:Ioc.rar

0 0
原创粉丝点击