Ioc的实现及应用

什么是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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值