zoukankan      html  css  js  c++  java
  • 设计模式之初识IoC/DI(六)

    本篇和大家一起学习IoC和DI即控制反转和依赖注入。

    当然听上去这词语非常的专业,真不知道是怎么组出来的,看上去难归看上去难,但稍微理解一下也就这么回事了。

    首先我们要明白IoC/DI干嘛用的,不然别人问“你知道IoC/DI吗?”,“知道啊!”,“那干嘛用的?”,呵呵,就郁闷了,其实IoC/DI的作用就两个字——解耦,说一千道一万,还是离不开这两个字。所以,IoC/DI的作用就是解耦。

    至于为什么要解耦,解耦在面向对象开发中的重要性在这里就不做细说了。

    下面我们来认识一下它们的真面目吧!

    要理解IoC/DI两个概念,就必须搞清楚如下问题:

    • 参与者都有谁?
    • 依赖:谁依赖于谁?为什么需要依赖?
    • 注入:谁注入谁?到底注入了什么?
    • 控制反转:谁控制谁?控制什么?为什么叫反转?有没有正向呢?正向又是什么?
    • 依赖注入和控制反转是同一概念吗?

    下面来简要回答一下上述问题,把这些问题搞明白了,也就明白了IoC/DI。

    1. 参与者都有谁:一般有三方参与,一个是某个对象,一个是IoC/DI容器,还有就是某个对象的外部资源。

        注:某个对象指任意一个普通的对象,IoC/DI容器简单说就是用来实现IoC/DI功能的一个框架程序,比如现在有许多IoC/DI框架(Unity、Spring.NET、Autofac),对象的外部资源指对象需要的,但是从对象外部获取的,都统称资源,比如对象需要其他对象。

    1. 谁依赖于谁:当然是某个对象依赖于IoC/DI容器
    2. 为什么需要依赖:因为对象需要IoC/DI的容器来提供对象需要的外部资源。
    3. 谁注入谁:IoC/DI的容器注入某个对象
    4. 到底注入了什么:就是注入某个对象所需要的外部资源,说完整点就是IoC/DI的容器将某个对象所需要的外部资源注入了该对象。
    5. 谁控制谁:IoC/DI的容器来控制对象
    6. 控制什么:主要是控制对象实例的创建
    7. 为什么叫反转:反转是相对与正向而言的。
    8. 正向又是什么:通常情况下的应用程序,如果在A里使用C,一般我们会直接创建C的对象,也就是说,在A类中主动获取所需要的外部资源,这种情况被成为正向的,那什么是反向呢?就是A类不再主动去获取C,而是被动等待,等待IoC/DI的容器获取一个C的实例,然后反向地注入到A类中。 

    先看没有IoC/DI的时候,常规A类使用C的示意图

     

     

    当有了IoC/DI的容器后,A类不再主动去创建C了,而是被动等待,等待IoC/DI的容器获取C的实例,然后反向注入到A类中。

     

    依赖注入和控制反转是同一概念吗?

    根据上面讲述,依赖注入和控制反转是对同一件事情的不同描述。依赖注入使用应用程序的角度去描述,我们可以把依赖注入描述的完整点:应用程序依赖容器创建并注入它所需要的外部资源。控制反转是从容器的角度去描述的,描述的完整点就是:容器控制应用程序,由容器反向的向应用程序注入其所需要的外部资源。

    好了,通过上述学习,大家都应该对IoC/DI有了基本了解,下面我们再来正式认识下依赖注入和控制反转。

    依赖注入中,依赖关系就像被注入的液体,我们可以在任何时候将依赖关系注入到模块中,而不只局限于编译是绑定。这种依赖关系是通过注入的方式完成的,就意味着我们可以随时更新,因为注入的液体与模块本身并无直接关联,举个不恰当的比喻,我们难道天生就要和针筒打交道吗?

    实现依赖注入的前提是面向接口编程,辅助的技术可以使用反射技术。

    MF.将依赖注入的形式分为三种:构造函数注入、设置方法注入和接口注入。

    接口注入是通过定义接口约束的方式实现依赖注入,会给容器带来设计的限制。

    而构造函数注入与设置方法(可以是属性)注入则是使用类的构造函数以及自定义的setter方法或属性进行依赖注入(关于这两点,可以参考第一篇《设计模式之UML类图的常见关系(一)》中的聚合和组合关系)。

    在这里我们也把第一篇聚合和组合关系类图拿到了。

    下面这个是使用Setter方法/属性实现依赖注入的。说白了就是定义一个Setter方法/属性,在该方法/属性内将对象关联起来。

    下面这个是构造函数的依赖注入,就是将Setter方法/属性换成了构造函数,但是请仔细看看两幅图片的代码和注入,什么时候使用Setter方法/属性注入,什么时候使用构造函数注入,当时在开发过程中,通常是使用构造函数进行依赖注入的。

    还有一个就是接口注入。

    这是我认为最不够优雅的一种依赖注入方式。要实现接口注入,首先ServiceProvider要给出一个接口定义:

    public interface InjectFinder {
        void injectFinder(MovieFinder finder);
    }

    接下来,ServiceUser必须实现这个接口:

    class MovieLister: InjectFinder
    {
          private MovieFinder finder;
          public void injectFinder(MovieFinder finder) {
          this.finder = finder;
        }
    }

    为什么现在介绍IoC/DI呢?

    想想,前面我们已经学习了三种工厂,那能不能将工厂和IoC/DI联系起来呢?好了,下面就自己想想!

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

     

  • 相关阅读:
    小白的Python之路_day1
    Vue---tab切换时不刷新
    Vue---第十五章使用VScode编写第一个脚本
    Vue---第十四章visual studio code使用
    Vue---第十三章基础运算和v-model
    Vue---第十二章批量下载模块
    vue---第十一章全局依赖环境区分
    Vue---第十章全局变量
    Vue---第九章NPM
    hadoop-Rpc使用实例
  • 原文地址:https://www.cnblogs.com/zxj159/p/3425168.html
Copyright © 2011-2022 走看看