• 认识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的源码,但一直没看,现在工作忙了,连博客也少写了,时间得好好分配,要保持学习。以上有什么说的不对的请指正,有什么好的建议或意见也请分享,谢谢!

  • 相关阅读:
    python练习--1、简易登录接口
    python--1、入门
    mysql数据库安装
    第八章总结
    第七章总结
    第三周总结
    第二周总结
    if、switch语句
    2章总结
    1月14日总结
  • 原文地址:https://www.cnblogs.com/HopeGi/p/3750802.html
Copyright © 2020-2023  润新知