IoC和DI的理解

1 概述

当咱们想闭上眼睛想如何让咱们的软件更加可用可维护时,咱们总能想到一个词:松耦合。在这篇文章中,主要讲述了模块间存在的依赖关系,但这种依赖关系违背了依赖倒置原则。在这以后,咱们将讨论一种解除软件依赖关系的设计模式——IoC,以及它的两种实现方法:依赖注入(DI)和服务定位。最后咱们简单地列下当前流行的IoC容器工具。html

目录spring

  • 依赖
  • 依赖倒置原则(DIP)
  • 控制反转IoC:解除两个模块间的直接依赖关系
  • 依赖注入(DI)
  • 服务定位(Service Locator)
  • IoC容器

2 依赖

当一个模块/类使用另外一个模块/类,即存在了一种依赖关系。sql

示例场景:数据库

在这里,咱们使用销售系统中保存订单的场景。好比,咱们当前的需求是将数据保存到SQL Server中。在这里咱们只关注业务层与数据持久层之间的依赖关系。编程

示例v1:设计模式

    public class SQLServerOrderDAL
    {
        public void Add() 
        {
            Console.WriteLine("The order was added in into sql server database.");
        }
    }

    public class OrderManager
    {
        public void AddOrder() 
        {
            SQLServerOrderDAL orderDAL = new SQLServerOrderDAL();
            orderDAL.Add();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            OrderManager orderManager = new OrderManager();
            orderManager.AddOrder();

            Console.ReadLine();
        }
    }
View Code

3 依赖倒置原则(DIP)

在这个时候,当公司的牛XX业务人员将这个销售系统又卖给了另外一家公司,你们都HAPPY。 可是对方公司惟一但愿数据保存到ORACLE,由于他们其它的软件已经购买了ORACLE受权,而且不想再购买SQL SERVER受权。即软件须要支持数据库更换,咱们应该如何解决oracle

依赖倒置原则(DIP)异步

高层模块不该依赖于低层模块,二者应该依赖于抽象。ide

抽象不不该该依赖于实现,实现应该依赖于抽象。函数

 

上述示例v1中,OrderManager依赖于OrderDAL. 即高层模块(OrderManager)直接依赖于实现(OrderDAL), 而不是依赖于抽象。下面咱们为数据持久层添加一层抽象,让业务层和数据持久实现层都依赖于抽象。

示例v2:

    public interface IOrderDAL
    {
        void Add();
    }

    public class OracleOrderDAL:IOrderDAL
    {
        public void Add()
        {
            Console.WriteLine("The order was added in into oracle database.");
        }
    }

    public class SQLServerOrderDAL:IOrderDAL
    {
        public void Add()
        {
            Console.WriteLine("The order was added in into sql server database.");
        }
    }

    public class OrderManager
    {
        public void AddOrder() 
        {
            IOrderDAL orderDAL = new OracleOrderDAL();
            orderDAL.Add();
        }
    }

class Program
    {
        static void Main(string[] args)
        {
            OrderManager orderManager = new OrderManager();
            orderManager.AddOrder();

            Console.ReadLine();
        }
    }
View Code

 

4 控制反转IoC

程序到这里,数据访问层已经添加一层抽象,即业务层和数据持久层都依赖于抽象。可是,注意这里,依然存在都依赖,即业务层依然要直接依赖于低层的数据持久实现层。当更换数据库时,会有不少这样的代码要更换。你知道我在说什么的..这仍是太恶心…

文章到这里了,咱们先说说控制反转——IoC(Inversion of Control), 网上关于IoC的解释不少,我比较喜欢这种http://www.cnblogs.com/liuhaorain/p/3747470.html:

它为相互依赖的组件提供抽象,将依赖(低层模块)对象的得到交给第三方(系统)来控制即依赖对象不在被依赖模块的类中直接经过new来获取

 

在多数状况下,上面的解释已经够用了,更广义一些的解释我认为是:

相对于过程式编程中,代码按顺序一步步执行,控制反转强调的是,将控制权交出,让第三方来控制程序的执行。

即除了将对象建立的工做交给第三方(咱们主要关心的,如依赖注入和服务定位),IoC应该还包括将流程的控制转交出去,如事件,Callback 委托,观察者模式,异步等

在接下来的文章中,咱们主要讨论依赖注入和服务定位。

5 依赖注入(DI)

依赖注入DI——Dependence Injection, 是一种IoC的实现方式。即将依赖对象的建立和绑定工做转移到第三者(调用方)。即 若是A对象依赖于B或C对象,那么就将B或C对象的建立工做转到A对象的调用方去。在上面示例中,将OracleOrderDAL或SQLServerOrderDAL的建立工做和绑定到IOrderDAL的工做转移到OrderManager的调用方中去,即具体对象建立的选择权移交到更高层的调用方法中。

依赖注入又分构造函数注入,属性注入和接口注入。我认为接口注入并很差用,因此这里只作构造函数和属性注入的示例。

5.1 构造函数注入

就是经过构造函数,传递依赖项。在这里,经过OrderManager的构造函数传入SQLServerOrderDAL或OracleOrderDAL

示例v3

    public class OrderManager
    {
        private IOrderDAL _orderDAL;

        public OrderManager(IOrderDAL orderDAL)
        {
            this._orderDAL = orderDAL;
        }

        public void AddOrder()
        {

            this._orderDAL.Add();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            IOrderDAL orderDAL = new SQLServerOrderDAL();
            //IOrderDAL orderDAL = new OracleOrderDAL();
           
            OrderManager orderManager = new OrderManager(orderDAL);
            orderManager.AddOrder();

            Console.ReadLine();
        }
    }
View Code

5.2 属性注入

即经过属性传入依赖项。在这里,能过OrderManager的OrderDA属性项,传入SQLServerOrderDAL或OracleOrderDAL

示例4

    public class OrderManager
    {
        private IOrderDAL _orderDAL;

        public IOrderDAL OrderDAL 
        {
            set { this._orderDAL = value; }
            get { return this._orderDAL; }
        }

        public void AddOrder() 
        {

            this._orderDAL.Add();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            IOrderDAL orderDAL = new SQLServerOrderDAL();
            //IOrderDAL orderDAL = new OracleOrderDAL();
           
            OrderManager orderManager = new OrderManager();
            orderManager.OrderDAL = orderDAL;
            orderManager.AddOrder();

            Console.ReadLine();
        }
    }
View Code

6 服务定位(Service Locator)

服务定位SL——Service Locator, 也是一种IoC的实现方式。即将依赖对象的建立和绑定工做转移到第三者(另外一个模块)。即 若是A对象依赖于B或C对象,那么就将B或C对象的建立工做转到F对象中去。在上面示例中,将OracleOrderDAL或SQLServerOrderDAL的建立工做和绑定到IOrderDAL的工做转移到Factory中去, 即具体对象的建立选择权移交给Factory中。

示例v5

    public class Factory
    {
        public static IOrderDAL GetOrderDAL() 
        {
            //string type = "SQLServer";
            string type = "Oracle";
            string assemblyName = string.Format("v5_{0}DAL",type);
            string typeName = string.Format("{0}.{1}OrderDAL",assemblyName,type);
            return (IOrderDAL)Assembly.Load(assemblyName).CreateInstance(typeName);
        }
    }

    public class OrderManager
    {
        public void AddOrder() 
        {
            IOrderDAL orderDAL = Factory.GetOrderDAL();
            orderDAL.Add();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            OrderManager orderManager = new OrderManager();
            orderManager.AddOrder();

            Console.ReadLine();
        }
    }
View Code

7 IoC容器

下面是一些主流的IoC容器工具以供参考

1. Unity:  http://unity.codeplex.com/

2. Ninject:  http://www.ninject.org/

3. Autofac:  http://code.google.com/p/autofac/

4. Spring.NET: http://www.springframework.net/

Unity示例v6

    public class OrderManager
    {
        private IOrderDAL _orderDAL;

        public OrderManager(IOrderDAL orderDAL)
        {
            this._orderDAL = orderDAL;
        }

        public void AddOrder()
        {

            this._orderDAL.Add();
        }
    }

    class Program
    {
        
        static void Main(string[] args)
        {
            UnityContainer container = new UnityContainer();
            //container.RegisterType<IOrderDAL, SQLServerOrderDAL>();
            container.RegisterType<IOrderDAL, OracleOrderDAL>();

            OrderManager orderManager = container.Resolve<OrderManager>();
            orderManager.AddOrder();

            Console.ReadLine();
        }
    }
View Code

上面是一些我关于IoC和DI的理解,若有不对的地方,欢迎提出讨论。

 

相关连接:

Inversion of Control Containers and the Dependency Injection pattern

Inversion of Control and Dependency Injection: Working with Windsor Container

Dependency Injection (DI) vs. Inversion of Control (IOC)
Inversion of Control – An Introduction with Examples in .NET

Understanding Inversion of Control, Dependency Injection and Service Locator

Dependency Injection

Dependency Inversion Principle, IoC Container, and Dependency Injection

Unity Container Introduced by MSDN

相关文章
相关标签/搜索