依赖倒置,控制反转,依赖注入 其实很简单

先用一句最简单(粗暴)解释 开篇

  • 上层模块不应该依赖于底层模块,它们都应该依赖于抽象
  • 抽象不应该依赖于细节,细节应该依赖于抽象

首先,让我们持有以下几个问题:

什么是依赖倒置?
什么是控制反转?
什么是依赖注入?

说实话,刚看到这几个词的时候,有点懵逼,不知道到底是啥意思,翻了几篇博客,看的我更是懵逼。直到多翻了几篇之后,才恍然大悟,哦,原来我经常在用啊。于是记录一下我的理解。

image-20191206174104536

本篇可以帮你理清这几个关键词的意义,重新梳理自己的思想。

什么是依赖倒置呢?

  • 上层模块不应该依赖于底层模块,它们都应该依赖于抽象

初学者看到这句解释,估计都想骂人了。而我们大多数同学往往总是解释时带着这句话,的确言简意赅。

我个人的理解:依赖倒置其实就相当于是 面向接口开发的 一种体现。


听起来很高大上,我直接用两段代码一探究竟吧:
public class Test {
    public static void main(String[] args) {
        Teacher teacher=new Teacher();
        teacher.initWang();
    }
}


/* 体育老师 */
class Teacher{
    private Wang wang;

    public void initWang(){
        wang=new Wang();
        wang.play();
    }


}

/* 喜欢的运动 */
interface IMotion {
    void play();
}

/* 学生 */
class Wang implements IMotion{

    @Override
    public void play() {
        System.out.println("wang 喜欢 踢足球");
    }
}

在上面的代码中,我们有一个测试类 Test,和一个体育老师类 Teacher , IMotion的运动接口,和一个学生Wang

运行我们的Test测试例子,会打印 ”wang 喜欢 踢足球“;


如果我们现在想再加入一个学生 Li,这个时候就需要更改 Teacher类了,比如再增加一个方法 initLi

如下:


/* 体育老师 */
class Teacher{
    private Wang wang;
    private Li li;

    public void initWang(){
        wang=new Wang();
        wang.play();
    }

    public void initLi(){
        li=new Li();
        li.play();
    }
}

/* 学生 */
class Li implements IMotion{

    @Override
    public void play() {
        System.out.println("li 喜欢 打篮球");
    }
}

我知道有些同学现在可能想骂了,这个博主是傻子吗,直接不会用接口对象吗。别急,我们慢慢过渡。



依赖倒置版本

public class Test {
    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        teacher.play();
    }
}


/* 体育老师 */
class Teacher {
    private IMotion iMotionWang;
    private IMotion iMotionLi;
    public Teacher(){
        iMotionLi=new Li();
        iMotionWang=new Wang();
    }

    public void play() {
        iMotionWang.play();
        iMotionLi.play();
    }

}

有些同学可能就要喊了?这不就我经常写的吗,这就叫 依赖倒置

没错,你没有理解错,虽然这个demo现在还存一些问题(比如谁没事new两个接口),但是它已经 具备了依赖倒置的思想

在前面的版本,我们一直new 的是具体的实例,针对具体的学生去操作,而现在我们应对的是它的抽象类,我们的的思想其实已经改变了。

那有些同学可能会问了,那这句话 抽象不应该依赖于细节,细节应该依赖于抽象 你怎么解释?

仔细思考一下,我们刚才写的这个接口,是不是就是这个理念,Teacher 老师类需要的是 学生具体喜欢的运动这个行为,在接口的形式下,我们无论增加多少学生,都不会影响老师这个类(不要注意多个new)。



接下来我们再来看看第二个特性,控制反转:

我们再更改一下刚才的代码,如下:

public class Test {
    public static void main(String[] args) {
        Teacher teacher = new Teacher(new Wang());
        teacher.play();
    }
}


/* 体育老师 */
class Teacher {
    private IMotion iMotion;

    public Teacher(IMotion iMotion) {
        this.iMotion = iMotion;
    }

    public void play() {
        iMotion.play();
    }

}

大多数同学肯定又要喊了,这不就是我经常写代码时的版本吗,这就是控制反转?你骗谁呢?

没毛病,这个真的是控制反转,再对比一下上一个版本,我们将 new 的这一步交给了具体的测试类,而不用 Teacher类来操作,这样无论以后增加多少个学生类,Teacher 都不用更改。



我们再来看看 依赖注入:

其实我们刚在已经做了依赖注入,比如我们通过构造函数将 具体的 对象 传了进去。当然也可以通过 set 方法传递;

如下:

public class Test {
    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        teacher.setiMotion(new Wang());
        teacher.play();
    }
}


/* 体育老师 */
class Teacher {
    private IMotion iMotion;

    public void setiMotion(IMotion iMotion) {
        this.iMotion = iMotion;
    }

    public void play() {
        iMotion.play();
    }

}

看完上面是不是觉得很简单,依赖倒置其实也没什么吗,没错,很多看起来高深的名词我们如果不懂就会觉得它很牛逼,其实只要我们遵循设计模式,其实这些所谓的名词也没什么。上面的demo虽然看起来很简单,但是大家关注的点不应该在缺陷的demo上,而应该在代码的过渡上面,我们现在看这些操作,觉得很简单,那是因为我们已经写了太多业务代码,设计模式肯定经常涉及,所以觉得不难。

如果是新同学的话,我建议你仔细感受过渡的过程,体会面向接口开发的快乐。


当然以上这只是我个人的理解,如果有偏差,也希望大家不吝赐教。

感谢链接,讲解依赖倒置

发布了97 篇原创文章 · 获赞 643 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/petterp/article/details/103427150