zoukankan      html  css  js  c++  java
  • 我在项目中运用 IOC(依赖注入)--入门篇

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

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

    【个人理解】

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

    简单的来说就是在类型A中需要使用类型B的实例,而B实例的创建并不由A来负责,而是通过外部容器来创建。相比以往实例化对象的写法,确实很爽。

    以往实例化都是这样的:

     
    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,解耦了这种依赖关系。接下来看看我在项目中是怎么简单应用的。

    【项目简单试用】

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

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

    首先需要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 功能很多,这篇只不过是凤毛麟角,还有什么构造注入,属性注入、单例的应用。这些,将在下篇继续分享。希望大家继续关注,多多指教。

  • 相关阅读:
    CentOS7 配置登录前显示IP
    用indexOf方法实现 数组去重
    easyui datagrid checkbox 禁止点击方法
    EasyUI常用图标
    Markdown基本语法
    百度地图标记
    Activity中的单击事件-------使用匿名内部类实现简单的跳转效果
    java.lang.ClassFormatError: Extra bytes at the end of class file quartz/loader/MyCalcSalary
    java.net.MalformedURLException: no !/ in spec
    Oracle 常见函数
  • 原文地址:https://www.cnblogs.com/jameslif/p/3542495.html
Copyright © 2011-2022 走看看