什么是依赖注入,能说说几个依赖注入的库吗?

幻昼 2020年06月05日 294次浏览

什么是依赖(Dependency)?

依赖是类与类之间的连接,依赖关系表示一个类依赖于另一个类的定义,通俗来讲就是一种需要,例如一个人(Person)可以买车(Car)和房子(House),Person类依赖于Car类和House类

    static class People {
        
        // 依赖house
        public void buy(House house) {

        }

        //依赖car
        public void buy(Car car) {

        }

    }

    static class House {

    }

    static class Car {

    }

依赖倒置(Dependency inversion principle)

依赖倒置是面向对象设计领域的一种软件设计原则软件设计有6大设计原则,合称SOLID

1、单一职责原则(Single Responsibility Principle,简称SRP)

  • 核心思想:应该有且仅有一个原因引起类的变更

2、里氏替换原则(Liskov Substitution Principle,简称LSP)

  • 核心思想:在使用基类的的地方可以任意使用其子类,能保证子类完美替换基类。

3、依赖倒置原则(Dependence Inversion Principle,简称DIP)

  • 核心思想:高层模块不应该依赖底层模块,二者都该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象;

4、接口隔离原则(Interface Segregation Principle,简称ISP)

  • 核心思想:类间的依赖关系应该建立在最小的接口上

5、迪米特法则(Law of Demeter,简称LoD)

  • 核心思想:类间解耦。通俗来讲:一个类对自己依赖的类知道的越少越好。

6、开放封闭原则(Open Close Principle,简称OCP)

什么是上层模块和底层模块?

公司管理层就是上,CEO是整个事业群的上层,那么CEO职能之下就是底层。然后,我们再以事业群为整个体系划分模块,各个部门经理以上部分是上层,那么之下的组织都可以称为底层。
由此,我们可以看到,在一个特定体系中,上层模块与底层模块可以按照决策能力高低为准绳进行划分。
那么,映射到我们软件实际开发中,一般我们也会将软件进行模块划分,比如业务层、逻辑层和数据层。
image.png

业务层中是软件真正要进行的操作,也就是做什么
逻辑层是软件现阶段为了业务层的需求提供的实现细节,也就是怎么做
数据层指业务层和逻辑层所需要的数据模型。

因此,如前面所总结,按照决策能力的高低进行模块划分。业务层自然就处于上层模块,逻辑层和数据层自然就归类为底层。

什么是抽象和细节?

象如其名字一样,是一件很抽象的事物。抽象往往是相对于具体而言的,具体也可以被称为细节,当然也被称为具象。
比如:

  1. 这是一幅画。画是抽象,而油画、素描、国画而言就是具体。
  2. 这是一件艺术品,艺术品是抽象,而画、照片、瓷器等等就是具体了。
  3. 交通工具是抽象,而公交车、单车、火车等就是具体了。
  4. 表演是抽象,而唱歌、跳舞、小品等就是具体。

上面可以知道,抽象可以是物也可以是行为。
具体映射到软件开发中,抽象可以是接口或者抽象类形式。

控制反转(IoC)

控制反转IoC是Inversion of Control的缩写,意思就是对于控制权的反转,对么控制权是什么控制权呢?

Person自己掌控着内部mDriveable的实例化。
现在,我们可以更改一种方式。将mDriveable的实例化移到Person外面。

class People {
    private Drivable mDrivable;

    public People(Drivable mDrivable) {
        this.mDrivable = mDrivable;
    }

    public void goOut() {
        System.out.println("go out");
        mDrivable.drive();
    }
}

class Drivable {
    public void drive() {
        
    }
}

就这样无论出行方式怎么变化,Person这个类都不需要更改代码了。

这种思想其实就是IoC,IoC是一种新的设计模式,它对上层模块与底层模块进行了更进一步的解耦。控制反转的意思是反转了上层模块对于底层模块的依赖控制。

比如上面代码,Person不再亲自创建Driveable对象,它将依赖的实例化的权力交接给了调用的类。而Person在IoC中又指代了IoC容器这个概念。

依赖注入(Dependency injection)

依赖注入,也经常被简称为DI,其实在上一节中,我们已经见到了它的身影。它是一种实现IoC的手段。什么意思呢?

为了不因为依赖实现的变动而去修改Person,也就是说以可能在Driveable实现类的改变下不改动Person这个类的代码,尽可能减少两者之间的耦合。我们需要采用上一节介绍的IoC模式来进行改写代码。

这个需要我们移交出对于依赖实例化的控制权,那么依赖怎么办?Person无法实例化依赖了,它就需要在外部(IoC容器)赋值给它,这个赋值的动作有个专门的术语叫做注入(injection),需要注意的是在IoC概念中,这个注入依赖的地方被称为IoC容器,但在依赖注入概念中,一般被称为注射器(injector)。

表达通俗一点就是:我不想自己实例化依赖,你(injector)创建它们,然后在合适的时候注入给我

实现依赖注入有3种方式:

  1. 构造函数中注入
  2. setter方式注入
  3. 接口注入