• 控制反转和依赖注入理解


    一、控制反转(IoC)

    (一) IoC是什么

      Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想,用来减低计算机代码之间的耦合度。 基本思想是:借助于“第三方”容器来降低具有依赖关系的对象之间的耦合 。Ioc意味着将你设计好的对象交给容器控制(由容器管理对依赖对象进行创建/监控/释放),而不是传统的在你的对象内部直接控制(通过是直接new一个依赖对象)。如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:

    1. 软件系统在没有引入IOC容器之前,对象A依赖于对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B,控制权都在自己手上。
    2. 软件系统在引入IOC容器之后,这种情形就完全改变了,由于IOC容器的加入,对象A与对象B之间失去了直接联系,所以,当对象A运行到需要对象B的时候,IOC容器会主动创建一个对象B注入到对象A需要的地方。

      通过前后的对比,我们不难看出来:对象A获得依赖对象B的过程,由主动行为变为了被动行为,控制权颠倒过来了,这就是“控制反转”这个名称的由来

      ●谁控制谁,控制什么:们直接在对象A内部通过new进行创建对象B,是程序主动去创建依赖对象B(应用程序控制A的依赖对象B的创建);而IoC是有专门一个容器来创建对象B,(Ioc容器来控制对象B的创建);谁控制谁?当然是IoC 容器控制了对象A;控制什么?那就是主要控制了对象A获取依赖对象B手段(不只是对象包括比如文件等)。

      ●为何是反转,哪些方面反转了:有反转就有正转, 由我们自己在对象A中主动控制去直接获取依赖对象B,也就是正转 ;而 反转则是由Ioc容器来帮忙创建A及注入依赖对象B ;为何是反转?因为由容器帮我们查找及注入依赖对象B,对象A只是被动的接受依赖对象B,所以是反转;哪些方面反转了?依赖对象B的获取被反转了。

    图1 在使用Ioc容器前

    图2 在使用Ioc容器后

    (二)IoC能做什么

      传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。

      其实IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC容器来创建并注入它所需要的资源了

    二、依赖注入(DI)

    (一)什么是DI

      DI(Dependency Injection),即“依赖注入”,形象的说,即由容器动态的将某个依赖项注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。

    理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来简单分析一下,看一个简单的栗子

    A和B是强耦合时的代码:  

      class Program
        {
            static void Main(string[] args)
            {
                A a = new A();
                a.AFunc();
            }
        }
    public class A { B b; public A() { b = new B();//在生成A实例的时候直接new出来一个B,A和B强耦合,如果改变B的初始化方法(如变成new B(string bName)),A中的构造器也要随着修改 } public void AFunc() { b.BFunc(); } } public class B { public void BFunc() { Console.WriteLine("B中的方法"); } }

    依赖注入的方式对A和B进行解耦:将B对象实例 作为类A的构造器参数(也可以通过成员属性进行注入)进行注入,在调用类A 构造器之前,类B实例已经被初始化好了。像这种非自己主动初始化依赖,而通过外部传入依赖对象的方式,我们就称为依赖注入

     class Program
        {
            static void Main(string[] args)
            {
                B myb = new B();
                A mya = new A(myb);//在A的构造器执行前b的实例已经创建了,B的初始化方法修改为 new B(string bName),A的构造器不用修改
                mya.AFunc();
                Console.ReadKey();
            }
        }
    
        public class A
        {
            B b;
            public A(B b)
            {
                this.b = b;//B的实例作为参数传入A的构造器
            }
            public void AFunc()
            {
                b.BFunc();
            }
        }
    
        public class B
        {
            public void BFunc() { Console.WriteLine("B中的方法"); }
    
        } 

    (二)IoC和DI的关系

    我们已经分别解释了IoC和DI的概念。它们的关系如下:

    • 控制反转Ioc是一种思想
    • 依赖注入DI是一种设计模式

    IoC是一种思想,DI是实现IoC的一种途径,目的是借助于“第三方”容器来降低具有依赖关系的对象之间的耦合。使用IoC容器(Autofac/Spring/Ninject等)可以将对类的依赖从编译时推迟到运行时。

    参考文章: 

      1、控制反转(IoC)与依赖注入(DI)

      2、我的控制反转,依赖注入和面向切面编程的理解

  • 相关阅读:
    May 1 2017 Week 18 Monday
    April 30 2017 Week 18 Sunday
    April 29 2017 Week 17 Saturday
    April 28 2017 Week 17 Friday
    April 27 2017 Week 17 Thursday
    April 26 2017 Week 17 Wednesday
    【2017-07-04】Qt信号与槽深入理解之一:信号与槽的连接方式
    April 25 2017 Week 17 Tuesday
    April 24 2017 Week 17 Monday
    为什么丑陋的UI界面却能创造良好的用户体验?
  • 原文地址:https://www.cnblogs.com/wyy1234/p/9088186.html
Copyright © 2020-2023  润新知