Skip to content

从前有个人叫小明,小明有三大爱好,逛知乎,打游戏,抢红包

介绍完Spring的IOC和DI的概念后,我们会发现这两个概念的最终目标就是:充分解耦,具体实现靠:

  • 使用IOC容器管理bean(IOC)
  • 在IOC容器内将有依赖关系的bean进行关系绑定(DI)
  • 最终结果为:使用对象时不仅可以直接从IOC容器中获取,并且获取到的bean已经绑定了所有的依赖关系.
js
class Ming extends Person
{
    private String name;
    private int age;

    void read(){
        //逛知乎
    }

    void play(){
        //打游戏
    }

    void grab(){
        //抢红包
    }

}

但是小明作为一个人类,无法仅靠自己就完成上述功能,他必须依赖一部手机,所以他买了一台iPhone6

js
class iPhone6 extends Iphone
{
    void read(String name) {
        System.out.println(name + "打开了知乎然后编了一个故事");
    }

    void play(String name) {
        System.out.println(name + "打开了Apex并开始白给");
    }

    void grab(String name) {
        System.out.println(name + "开始抢红包却只抢不发");
    }
}

小明很珍惜自己买的新手机,每天把它牢牢控制在手心,于是小明变成了这样

js
class Ming extends Person {
    private String name;
    private int age;

    public Ming(String name, int age) {
        this.name = name;
        this.age = age;
    }

    void read() {
        //逛知乎
        new iPhone6().read(name);
    }

    void play() {
        //打游戏
        new iPhone6().play(name);
    }

    void grab() {
        //抢红包
        new iPhone6().grab(name);
    }
}

今天是周六,小明不用上班,于是他起床,并依次逛起了知乎,打起了游戏,并抢了个红包。

js
Ming ming = new Ming("小明", 18);  //小明起床
ming.read();
ming.play();
ming.grab();

这个时候,我们可以在命令行里看到输出如下

输出

小明打开了知乎然后编了一个故事 小明打开了Apex并开始白给 小明开始抢红包却只抢不发

  • 这一天,小明过得很充实,他觉得自己是世界上最幸福的人。

  • 但随着时间的推移,手机越来越卡顿,电池寿命也越来越短,到了冬天还会冻关机了,小明很难过,他意识到他需要换一部手机了

  • 为了获得更好的使用体验,小明一咬牙一跺脚,买了一台iPhone14 Pro Max,但他现在遇到了一个问题,他之前太过依赖那台iPhone6了,他们已经深深的耦合在一起了,如果要换手机,他必须要拿螺丝刀改造自己,将自己体内所有方法中的iPhone6换成iPhone14

js
class Ming extends Person {
    private String name;
    private int age;

    public Ming(String name, int age) {
        this.name = name;
        this.age = age;
    }

    void read() {
        //逛知乎
        new iPhone14().read(name);
    }

    void play() {
        //打游戏
        new iPhone14().play(name);
    }

    void grab() {
        //抢红包
        new iPhone14().grab(name);
    }
}
  • 虽然过程很辛苦,但小明觉得自己是值得的。随后在晚高峰挤地铁的时候,小明的手机被偷了。为了应急,小明只好重新使用那部刚刚被遗弃的iphone6,但是一想到那漫长的改造过程,小明的心里就说不出的委屈
  • 他觉得自己过于依赖手机了,为什么每次手机出什么问题他都要去改造他自己,这不仅仅是过度耦合,简直是本末倒置,他向天空大喊,我不要再控制我的手机了。
  • 天空中的造物主,也就是作为程序员的我,听到了他的呐喊,我告诉他,你不用再控制你的手机了,交给我来管理,把控制权交给我。这就叫做控制反转。
  • 小明听到了我的话,他既高兴,又有一点害怕,他跪下来磕了几个头,虔诚地说到:“原来您就是传说中的造物主。我听到您刚刚说了 控制反转 四个字,就是把手机的控制权从我的手里交给你,但这只是您的想法,是一种思想罢了,要用什么办法才能实现控制反转,又可以让我继续使用手机呢?”
  • “呵“,身为造物主的我在表现完不屑以后,扔下了四个大字,“依赖注入!”
  • 接下来,伟大的我开始对小明进行惨无人道的改造
js
class Ming extends Person {
    private String name;
    private int age;
    private Phone phone;

    public Ming(String name, int age, Phone phone) {
        this.name = name;
        this.age = age;
        this.phone = phone;
    }

    void read() {
        //逛知乎
        this.phone.read(name);
    }

    void play() {
        //打游戏
        this.phone.play(name);
    }

    void grab() {
        //抢红包
        this.phone.grab(name);
    }
}
  • 随后我们来模拟小明的一天
js
Phont phone = new Iphone14();   //创建一个iphone14的实例
if(phone.isBroken() == true){   //如果iphone14不可用,则使用旧版手机
    phone = new Iphone6();
}
Ming ming = new Ming("小明",18,phone);    //小明不用关心是什么手机,他只要玩就行了。
ming.read();
ming.play();
ming.grab();
  • 我们先看一下iphone14 是否可以使用,如果不可以使用,则直接换成iphone6,然后唤醒小明,并把手机塞到他的手里,换句话说,把他所依赖的手机直接注入到他的身上,他不需要关心自己拿的是什么手机,他只要直接使用就可以了。
  • 这就是依赖注入
  • 随后小明的生活开始变得简单了起来,而他把省出来的时间都用来写笔记了,他在笔记本上这样写到

总结

我曾经有很强的控制欲,过度依赖于我的手机,导致我和手机之间耦合程度太高,只要手机出现一点点问题,我都要改造我自己,这实在是既浪费时间又容易出问题。自从我把控制权交给了造物主,他每天在唤醒我以前,就已经替我选好了手机,我只要按照平时一样玩手机就可以了,根本不用关心是什么手机。即便手机出了问题,也可以由造物主直接搞定,不需要再改造我自己了,我现在买了七部手机,都交给了造物主,每天换一部,美滋滋! 我也从其中获得了这样的感悟: 如果一个类A 的功能实现需要借助于类B,那么就称类B是类A的依赖,如果在类A的内部去实例化类B,那么两者之间会出现较高的耦合,一旦类B出现了问题,类A也需要进行改造,如果这样的情况较多,每个类之间都有很多依赖,那么就会出现牵一发而动全身的情况,程序会极难维护,并且很容易出现问题。要解决这个问题,就要把A类对B类的控制权抽离出来,交给一个第三方去做,把控制权反转给第三方,就称作控制反转(IOC Inversion Of Control)。控制反转是一种思想,是能够解决问题的一种可能的结果,而依赖注入(Dependency Injection)就是其最典型的实现方法。由第三方(我们称作IOC容器)来控制依赖,把他通过构造函数、属性或者工厂模式等方法,注入到类A内,这样就极大程度的对类A和类B进行了解耦。