我在项目中运用 IOC(依赖注入)--入门篇

以前就听同事说过依赖注入(dependency injection)、控制反转(Inversion of Control)。起初听的是一头雾水,试着在项目中运用了几回,总算明白了一些,抛砖引玉,与你们分享一下拙见。数据库

其实依赖注入和控制反转指的都是同一个事情。什么是依赖注入了???架构

【我的理解】app

以最熟悉的三层架构的项目来讲,BLL层依赖DAL层,UI层依赖于BLL层,层层之间紧密联系。代码里处处都是new 对象。认识IOC后,发现IOC最大的好处就是解耦了对这种层级之间的依赖关系进。程序自己不在负责对象的建立和维护,而交给外部容器(IOC容器)来负责。外部容器在运行时动态地将依赖的对象注入到组件之中。函数

简单的来讲就是在类型A中须要使用类型B的实例,而B实例的建立并不禁A来负责,而是经过外部容器来建立。相比以往实例化对象的写法,确实很爽。工具

以往实例化都是这样的:this

public class A
{
    public A(B b)
    {
        this.B = b;
    }
 
    public B B { get; set; }
 
    public void Test(B b)
    {
        Console.WriteLine(b.ToString());
    }
}

A 类受B类的影响很大。A类的构造函数中,实例化B,且在A类的Test的方法中,须要判断B类是否是被实例化。A即建立B又须要维护B。用了IOC,解耦了这种依赖关系。接下来看看我在项目中是怎么简单应用的。spa

 

【项目简单试用】code

一开始用的IOC容器是Unity,四个字,短小精干(用了有段日子。还有好多功能还需不断去探索) 。网上还有其它的IOC容器,没有去了解过(我的认为,能把一个工具用会,用熟,用精,才是王道。对象

我把项目中的一段代码摘出来,项目需求大体上是项目有个数据统计,它下面有三种不一样的统计类型,须要与数据库交互,而后展现到页面。blog

首先须要Unity的类库,利用VS2012的库程序包管理工具去下载Unity的类库。

项目的结构是这样,标准的是三层架构,BLL和DAL都有接口层IBLL,IDAL。

首先咱们按照不用IOC的方式来实现这个小需求。

IDAL,IBLL 建立接口 IAnalyse 接口里有个方法

public interface IAnalyse
    {
        /// <summary>
        /// 显示结果
        /// </summary>
        void ShowResult();
    }

DAL 层引用IDAL,建立类 Analyse.cs 

public class Analyse:IDAL.IAnalyse
    {
        public void ShowResult()
        {
            Console.WriteLine("分析底层数据库交互");
        }
    }

BLL层引用IDAL,DAL,IBLL 建立 类 Analyse.cs 

        /// <summary>
        /// 显示结果
        /// </summary>
        public void ShowResult()
        {
            ////之前思路 须要引用IBLL,IDAL,DAL
            IDAL.IAnalyse dal = new DAL.Analyse();
            dal.ShowResult();
        }

 UI层用控制台应用程序来代替。需引用IBLL,BLL

class Program
    {
        static void Main(string[] args)
        {
            OldMethod();
            Console.ReadKey();
        }

        /// <summary>
        /// 在使用IOC前的写法。须要引入IBLL,BLL
        /// </summary>
        static void OldMethod()
        {
            IBLL.IAnalyse bll = new BLL.Analyse();
            bll.ShowResult(); 
        }
    }

按照之前的方法,每一个层咱们都在不断的new 对象。写到这里发现这些都是很中规中矩的写法,之前老师教的也是这样,可能你会以为没啥很差的。我就假如:BLL.Analyse 的构造函数须要参数,参数为Class B ,去掉无参的构造函数,你是否是全部new 对象的地方都要更改。小项目也许尚未问题,若是是上百万的大项目咋办。这就是所谓的层与层之间的耦合度高。(我的拙见,多多指教

接下来咱们用 IOC 来解耦。在Program.cs 增长 IOCMethod1 方法

static void Main(string[] args)
        {
            //OldMethod();
            IOCMethod1();
            Console.ReadKey();
        }

static void IOCMethod1()
        {
            IUnityContainer container=new UnityContainer();
            ////在容器中注册一种类型,它是一个类型的映射,接口类型是IAnalyse,但愿返回的类型是Analyse
            container.RegisterType<IBLL.IAnalyse, BLL.Analyse>();
            ////第二种写法
            //container.RegisterType(typeof (IBLL.IAnalyse), typeof (BLL.Analyse));
            IBLL.IAnalyse bll = container.Resolve<IBLL.IAnalyse>();
            bll.ShowResult();
        }

使用unity就三步:

第一,new IOC 容器

第二,调用RegisterType 注册类型。这里有多种注册形式。能够注册单例的、构造函数有参数的。

第三,调用Resolve 建立对象

认识IOC 简单吧 O(∩_∩)O

到这,你会发现,UI层 仍然引用了IBLL,BLL,RegisterType方法须要这两个类库。既然是解耦,就得解耦完全些。有什么方法???

我在Core层 DependencyRegister.cs. 创建一个静态方法,在程序运行开始的时候,注册全部的类型。UI 层移除BLL ,引用Core 

namespace Core
{
    /// <summary>
    /// 类型注册
    /// </summary>
    public class DependencyRegister
    {


        public static IUnityContainer DependencyRegisterContainer()
        {
            IUnityContainer container = new UnityContainer();
            container.RegisterType<IBLL.IAnalyse, BLL.Analyse>()
                     .RegisterType<IDAL.IAnalyse, DAL.Analyse>();
            return container;
        }
    }
}


////UI层 先移除BLL,引用Core
static void Main(string[] args)
        {
            
            IOCMethod2();
            Console.ReadKey();
        }

static void IOCMethod2()
        {

  IUnityContainer container = DependencyRegister.DependencyRegisterContainer();
IBLL.IAnalyse bll = container.Resolve<IBLL.IAnalyse>(); 
bll.ShowResult();
    }

这样达到了解耦的目标,如何须要更改类的构造函数,只需更改Core DependencyRegister.cs 就能够了。

 

【其它解耦方式】

创建core是用了本身得方法来实现解耦的,其实unity还有更以为,经过配置文件 app.config 来实现。用的是 Microsoft.Practices.Unity.Configuration.dll

    <!-- 程序集-->
    <assembly name="IBLL"/>
    <assembly name="IDAL"/>
    <!--要返回的类型-->
    <alias alias="BLLAnalyse1" type="BLL.Analyse, BLL" />
    <container name="ContainerAnalyse">
      <register type="IBLL.IAnalyse" name="BLLAnalyse1" mapTo="BLLAnalyse1" />
    </container>
private static void IOCMethod3()
        {
            ////经过配置文件注册全部类型
            IUnityContainer container=new UnityContainer();
            UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
            section.Configure(container, "ContainerAnalyse");
            IBLL.IAnalyse bll = container.Resolve<IBLL.IAnalyse>("BLLAnalyse1");
            bll.ShowResult();
        }

 

【投机取巧】

不管是使用全局方法,或者 配置文件,都是注册类的形式不一样。每种方法都须要调用Resolve 来建立对象。有没有连改方法都不用调用的形式。

不用多说,直接上代码:

 

namespace BLL
{
    public class Analyse:IBLL.IAnalyse
    {
        ////使用依赖注入
        [Dependency]
        public IDAL.IAnalyse dal { get; set; }
        /// <summary>
        /// 显示结果
        /// </summary>
        public void ShowResult()
        {
            ////之前思路 须要引用IBLL,IDAL,DAL
            //IDAL.IAnalyse dal = new DAL.Analyse();
            
            
            dal.ShowResult();
        }
    }
}

使用[Dependency]属性。说实话,它的用法还有些没有弄明白。但愿明白这个得多指教指教。

献丑了,有什么不对的地方但愿你们多多指教。Unity 功能不少,这篇只不过是百里挑一,还有什么构造注入,属性注入、单例的应用。这些,将在下篇继续分享。但愿你们继续关注,多多指教。

【源码下载】

相关文章
相关标签/搜索