一点即通 — 什么叫依赖注入

一点即通 : 什么叫依赖注入

可能有很多人现在还对依赖注入不太了解,或者觉得这是个很高深的东西,其实嘛,只要你了解其中逻辑和想法后,就知道这也并不是什么高深莫测的东西了。

接下来我就以一个小故事的例子来做说明,希望看完后能帮助你对此有所理解:

1. 汤姆和他的爱好

汤姆有 3 个爱好,分别是玩游戏、看视频和拍照。所以我们可以用以下代码表示:

public class Tom : Person
{
    private string _name;
    private int _age;

    public void PlayGames() 
    {
        //play games
    } 

    public void WatchVideos()
    {
        //watch Videos
    }

    public void Photography()
    {
        //photography
    }
}

但做为一个人,汤姆并不能直接自己去完成这些东西,所以他必须要借助其他设备,如一台手机,所以他买了一台 iPhone8 。然后我们可以将代码更新一下:

public class iPhone8 : iPhone
{
    public void PlayGames(string user="某人") 
    {
        Console.WriteLine(user + " 正在玩游戏");
    } 

    public void WatchVideos(string user="某人")
    {
        Console.WriteLine(user + " 正在看视频");
    }

    public void Photography(string user="某人")
    {
        Console.WriteLine(user + " 正在拍照");  
    }
}

汤姆非常爱惜他的手机,所以牢牢地控制着它,然后汤姆就变成了

public class Tom : Person
{
    private string _name;
    private int _age;

    public Tom()
    {
        this._name = "汤姆";
        this._age = 25;
    }

    public void PlayGames() 
    {
        //...省略万行代码...
        var phone = new iPhone8();
        phone.PlayGames(this._name);
    } 

    public void WatchVideos()
    {
        //...省略万行代码...
        var phone = new iPhone8();
        phone.WatchVideos(this._name);
    }

    public void Photography()
    {
        //...省略万行代码...
        var phone = new iPhone8();
        phone.Photography(this._name);
    }
}

星期天,汤姆在家休息,当一起床后又开始玩他的手机了

var tom = new Tom(); //起床了...
tom.PlayGames();
tom.WatchVideos();
tom.Photography();

然后我们可以在控制台中看到以下代码运行的结果

汤姆 正在玩游戏
汤姆 正在看视频
汤姆 正在拍照

2. 汤姆的快乐与悲伤

汤姆和手机曾经一起度过了一段美好的时光,一有空,他就会抱着手机,玩游戏,看视频,拍照,他觉得根本不需要女朋友,只要有手机就够了!

可谁曾想,反复的系统更新彻底击碎了他的梦想,手机越来越卡,电池续航时间也越来越短,直到有一天在寒风中,他的手机终于受不了寒冷,头也不回的关机了。

汤姆很伤心,他意识到自己必须换手机了。:worried:

为了得到更好的用户体验,汤姆咬着牙买了一部 iphone14,这部手机铃声响亮,电量很大,双卡双待,汤姆很喜欢,但是他遇到了一个问题,就是他太依赖之前原来的 iPhone 8 了,它们已经深深的耦合在了一起,如果要换手机,他就得拿起刀子来改造自己,把自己身上的 iphone 8 全部换成 iphone 14。

经过漫长的改造过程,汤姆最终把代码里的 iphone 8 全部换成了 iphone 14,虽然很辛苦,但是汤姆认为自己是幸福的。 :yum:

于是汤姆兴高采烈地带着手机去上班,结果在回来的路上被小偷偷走了。为了应急,汤姆只好把刚刚废弃的 iPhone 8 重新利用起来,但一想到漫长的改造过程,汤姆心里就有一种说不出的委屈,他觉得自己太依赖手机了,要重新改造自己,这不仅仅是过度耦合,这是本末倒置,他对着天空大喊,我不控制我的手机了!

天上的造物主,也就是我这个程序员,听到了他的哭声,我告诉他,你不需要再控制你的手机了,让我来管,把控制权给我。这就叫 控制反转(Inversion Of Control)。

3. 造物主的智慧

听到我的话,汤姆既高兴又有些害怕,他跪下磕了几个头,虔诚地说道:“原来您就是传说中的造物主,造物主大神。我听您刚才说了 控制反转 的话,就是说我将手机的控制权从我的手中交给您,但这只是您的想法,只是一种想法而已,要用什么方法才能实现 控制反转 同时又可让我继续使用手机?”

“呵”,作为造物主,我表示完不屑后,就把 依赖注入 这几个字给丢了过去!”

接下来,伟大的我开始对汤姆进行毫无人性的改造,变成了如下

public class Tom : Person
{
    private string _name;
    private int _age;
    private iPhone _phone; //将手机变成汤姆的一个属性

    public Tom(phone)
    {
        this._name = "汤姆";
        this._age = 25;
        this._phone = phone;
        Console.WriteLine("汤姆起床了!");
    }

    public void PlayGames() 
    {
        //...省略万行代码
        this._phone.PlayGames(this._name);
    } 

    public void WatchVideos()
    {
        //...省略万行代码
        this._phone.WatchVideos(this._name);
    }

    public void Photography()
    {
        //...省略万行代码
        this._phone.Photography(this._name);
    }
}

接下来,让其运行并模拟汤姆的一天吧

//创建 iPhone14 的实例
var phone = new iPhone14();
if(phone.isBroken()){
    //如果创建失败,则使用 iPhone 8
    phone = new iPhone8();
}
//汤姆此时根本不需要关心自己使用了哪个型号的手机
var tom = new Tom(phone);
tom.PlayGames();
tom.WatchVideos();
tom.Photography();

我们需要检查 iPhone14 能不能用,不能就换成 iPhone8,然后叫醒汤姆,也就是说,他所依赖的手机就直接注入到他身上,他不用关心手里拿的是什么手机,直接用就行,这就是 依赖注入

4. 汤姆的感悟

汤姆的生活开始变得简单起来,他把省下来的时间都用来写笔记了,他在笔记本上这样写道:

我以前控制欲很强,对手机依赖太多,导致我和手机耦合度很高,只要手机稍微出点问题,我就要改造自己,这样很浪费时间,也很容易失败。

自从我把控制权交给造物主之后,他每天在我起床之前就已经帮我选好了手机。我只要照常玩手机就行了,根本不需要关心手机,即使手机出了问题,直接让造物主修好就可以了,不用自己重新改造。

我买了七部手机,都交给造物主了,每天换一部,很开心!:laughing:

我还从中得到了这样的感悟:

如果一个 类A 的功能实现需要 类B 的帮助,那么 类B 就被说成是 类A 的依赖,如果 类B 是在 类A 内部实例化的,那么这两个类之间的关系就是高耦合的,一旦 类B 出了问题,类A 也需要改造。

如果这种情况很多,各个类之间依赖关系很多,那么就会出现牵一发而动全身的情况,这样的话,程序就会极难维护,而且很容易出问题。

要解决这个问题,就需要把 类B类A 的控制权抽离出来交给第三方去做,把控制权反转给第三方,这就叫 控制反转IOC)。

控制反转 是一种能够解决问题的思路和可能结果,依赖注入DI)就是其最典型的实现方式。第三方(我们称之为IOC容器)控制依赖,通过构造函数、属性或者工厂模式等方式,将依赖注入到 类A 中,从而很大程度上解耦了 类A类B

好了,汤姆都已有了不少的感悟了,不知道你是否也得到了一些感悟呢? :smirk:

代码部落

免费订阅以得到最新文章发布的通知

请放心,这个绝对不会是垃圾邮件
而且您随时也可以取消的

版权声明:
作者:winson
链接:https://www.coderblog.cc/2024/06/easy-to-understand-what-is-dependency-injection/
来源:代码部落中文站
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>
文章目录
关闭
目 录