关于java:依赖注入的真实用例是什么?

what is the real use case of dependency injection?

本问题已经有最佳答案,请猛点这里访问。

我理解依赖注入,但我真正不理解的是,依赖注入的用途是什么。

正如这里提到的,这有助于轻松测试代码(这是一种非常有用的测试技术,因为它允许模拟或删除依赖项),但是现在有很多模拟框架,如mockito、powermockito,它们可以很好地完成这些工作,而不是为什么要进行依赖项注入?

如果有人能用代码解释,那就太好了。

事先谢谢。


DI作为一种技术的主要用途是:

它导致代码更容易测试(使用模拟)。这意味着为了使用模拟框架(mockito等),您应该使用更多的DI。如果您不使用DI并编写直接实例化对象的代码,那么实际上您不能使用mockito来模拟依赖项。

假设你写代码来演奏管弦乐队。你的主要课程依赖于这么多其他的课程(也许是其他人写的)。

假设你写了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Orchestra {
  private Drums drum;
  private Violin violin;
  private Guitar guitar;

public Orchestra() {
    drum = new Drum();
    violin = new Violin();
    guitar = new Guitar();
}

public Music play(){
    // use above in some way to run your orchestra
    // start with violin
    // add some guitar and then bring in the drums too
}

}

现在,您要确保您在play中的逻辑能够准确地工作。当你上课时,你会发现音乐不是你所期望的。(也许开始的时候就开始打鼓了)。您想测试代码play的逻辑。你在这里怎么做?你无法控制你的依赖。您不知道Drum的代码或您自己在play()中的逻辑是否有问题。

你想在这里模仿Drum。但你不能轻易做到。因为您的代码不使用DI。它直接在内部实例化Drum

现在让我们使用DI,看看它有什么帮助。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Orchestra {
    private Drums drum;
    private Violin violin;
    private Guitar guitar;

    public Orchestra(Drums d,Violin v, Guitar g ) {
        drum = d;
        violin = v;
        guitar = g;
    }

    public Music play(){
        // use above in some way to run your orchestra
    }

}

有了这段代码,在您的测试中可以很容易地模拟出Drum

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class TestOrchestra {

    public void testPlay(){
        Drum mockDrum = mock(Drum.class);
        Violin mockViolin = mock(Violin.class);
        Guitar mockGuitar = mock(Guitar.class);
        // add mock behaviour to above , here you control precisely what these dependencies will do inside your code

        Orchestra orch = new Orchestra(mockDrum, mockViolin,mockGuitar);
        // now play and test your logic

    }

}

使用DI的第二个优点是它有助于改变程序更大部分的实现,而无需遍历整个代码。

再次提到上面的内容,假设您一直在使用特定类型的吉他(由代码在内部实例化)演奏管弦乐队。

现在你想换一把全新的电吉他,如果没有DI,你就必须打开你的Orchestra类,检查你在哪里创建Guitar并更改代码行。您必须确保代码的其他部分不会被无意中更改,并测试整个Orchestra,以确保工作正常。

有了DI,你可以避免所有这些。您只需将新的Guitar对象注入到构造函数中。就是这样。因为你自己测试了新的Guitar对象(并且它符合interface Guitar的合同),你可以放心,你的Orchestra代码不会因为注入新的吉他而被破坏。这对提高你的管弦乐队是一个更好的办法。


Dependency injection不是mocking frameworks的替代品。这是一项要求。如果您有硬的依赖关系,那么模拟依赖关系并因此测试代码就要困难得多。

DI还允许您拥有更松散耦合的代码。类可以使用其他类,只需注入它们,而不必知道如何构造(或获取)特定类的实例。