首页 > 技术文章 > 深入理解DIP、IoC、DI以及IoC容器

step-city 2016-08-29 17:07 原文

1、依赖倒置原则(DIP):一种软件架构设计的原则(抽象概念)。   依赖倒置原则,它转换了依赖,高层模块不依赖于低层模块的实现,而低层模块依赖于高层模块定义的接口

2、控制反转(IoC):一种反转流、依赖和接口的方式(DIP的具体实现方式)。

控制反转(IoC),它为相互依赖的组件提供抽象,将依赖(低层模块)对象的获得交给第三方(系统)来控制即依赖对象不在被依赖模块的类中直接通过new来获取。在图1的例子我们可以看到,ATM它自身并没有插入具体的银行卡(工行卡、农行卡等等),而是将插卡工作交给人来控制,即我们来决定将插入什么样的银行卡来取钱。

软件设计原则:原则为我们提供指南,它告诉我们什么是对的,什么是错的。它不会告诉我们如何解决问题。它仅仅给出一些准则,以便我们可以设计好的软件,避免不良的设计。一些常见的原则,比如DRY、OCP、DIP等。

软件设计模式:模式是在软件开发过程中总结得出的一些可重用的解决方案,它能解决一些实际的问题。一些常见的模式,比如工厂模式、单例模式等等。

3、依赖注入(DI):IoC的一种实现方式,用来反转依赖(IoC的具体实现方式)。

控制反转(IoC)一种重要的方式,就是将依赖对象的创建和绑定转移到被依赖对象类的外部来实现

依赖注入(DI),它提供一种机制,将需要依赖(低层模块)对象的引用传递给被依赖(高层模块)对象。通过DI,我们可以在Order类(订单类)的外部将SqlServerDal对象(数据库访问类)的引用传递给Order类对象。根据DIP原则,我们知道高层模块不应该依赖于低层模块,两者应该依赖于抽象。那么构造函数的参数应该是一个抽象类型。

方法一:

  1. 首选,我们需要定义SqlServerDal的抽象类型IDataAccess,并在IDataAccess接口中声明一个Add方法。
    public interface IDataAccess
    {
            void Add();
    }

     

  2. 然后在SqlServerDal类中,实现IDataAccess接口。
    public class SqlServerDal:IDataAccess
    {
           public void Add()
           {
               Console.WriteLine("在数据库中添加一条订单!");
           }
    }

     

  3.  接下来,我们还需要修改Order类。
    public class Order
    {
          private IDataAccess _ida;//定义一个私有变量保存抽象
          
            //属性,接受依赖   (也可以构造函数注入)
            public IDataAccess Ida
           {
               set { _ida = value; }
               get { return _ida; }
           }
     
           public void Add()
           {
               _ida.Add();
           }
    }

     

     

     

  4. OK,我们再来编写一个控制台程序。
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
     
    namespace DIPTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                SqlServerDal dal = new SqlServerDal();//在外部创建依赖对象
                Order order = new Order();//通过构造函数注入依赖
                order.Ida = dal;    //给属性赋值
                order.Add();
     
                Console.Read();
            }
        }
    }

     

  5. 从上面我们可以看出,我们将依赖对象SqlServerDal对象的创建和绑定转移到Order类外部来实现,这样就解除了SqlServerDal和Order类的耦合关系。当我们数据库换成Access数据库时,只需定义一个AccessDal类,然后外部重新绑定依赖,不需要修改Order类内部代码,则可实现Access数据库的操作。
  6. 定义AccessDal类:
    public class AccessDal:IDataAccess
    {
            public void Add()
            {
                Console.WriteLine("在ACCESS数据库中添加一条记录!");
            }
    }

     

  7. 然后在控制台程序中重新绑定依赖关系:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
     
    namespace DIPTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                 AccessDal dal = new AccessDal();//在外部创建依赖对象
                   Order order = new Order(dal);//通过构造函数注入依赖
     
                   order.Add();
     
                Console.Read();
            }
        }
    }

     

方法二:相比构造函数注入和属性注入,接口注入显得有些复杂,使用也不常见。具体思路是先定义一个接口,包含一个设置依赖的方法。然后依赖类,继承并实现这个接口。

  1. 首先定义一个接口IDAO: 
    public interface IDependent
    {
               void SetDependence(IDataAccess ida);//设置依赖项
    }

     

  2. 依赖类实现这个接口:
    public class Order : IDependent
     {
         private IDataAccess _ida;//定义一个私有变量保存抽象
     
         //实现接口(通过构造函数注入)
         public void SetDependence(IDataAccess ida)
         {
             _ida = ida;
         }
     
         public void Add()
         {
             _ida.Add();
         }
     
     }

     

  3. 控制台程序通过SetDependence方法传递依赖:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
     
    namespace DIPTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                AccessDal dal = new AccessDal();//在外部创建依赖对象
              Order order = new Order();
     
                order.SetDependence(dal);//传递依赖
     
                order.Add();
     
                Console.Read();
            }
        }
    }

     

IoC容器:依赖注入的框架,用来映射依赖,管理对象创建和生存周期(DI框架)。

具体内容参考:http://www.cnblogs.com/liuhaorain/p/3747470.html

推荐阅读