zoukankan      html  css  js  c++  java
  • IoC和DI的理解

    1 概述

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

    目录

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

    2 依赖

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

    示例场景:

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

    示例v1:

     View Code

    3 依赖倒置原则(DIP)

    在这个时候,当公司的牛XX业务人员将这个销售系统又卖给了另一家公司,大家都HAPPY。 但是对方公司唯一希望数据保存到ORACLE,因为他们其它的软件已经购买了ORACLE授权,并且不想再购买SQL SERVER授权。即软件需要支持数据库更换,我们应该如何解决

    依赖倒置原则(DIP)

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

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

     

    上述示例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();
            }
        }
    复制代码

     

    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();
            }
        }
    复制代码

    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();
            }
        }
    复制代码

    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();
            }
        }
    复制代码

    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();
            }
        }
    复制代码

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

     

  • 相关阅读:
    Java虚拟机(第二版) 学习笔记之Class类文件的结构
    JVM之深入浅出之垃圾收集算法
    Java虚拟机(第二版) 学习笔记之OutOfMemoryError
    Java虚拟机(第二版) 学习笔记
    平滑加权轮询负载均衡(轮询)算法
    java AQS(AbstractQueuedSynchronizer)同步器详解
    mybatis Interceptor拦截器代码详解
    aspectj编程简介
    Java并发编程阅读笔记-Java监视器模式示例
    我们该怎么结合日志做优化
  • 原文地址:https://www.cnblogs.com/wyBlog117/p/4629141.html
Copyright © 2011-2022 走看看