首页 > 解决方案 > 在两个简单类的上下文中掌握依赖注入

问题描述

我在掌握依赖注入时遇到了问题(或者让我说它的好处)。所以我决定写两段简单的代码,一段没有DI,另一段有DI。

所以我有一堂课A

public class A {
    public void foo(){
        B b = new B();
        b.fooB();
    }
}

如上所示,A取决于BB

public class B {
    public void fooB(){
        Log.e("s", "y");
    }
}

我们可以使用Alike

public void do(){
    A a = new A();
    a.foo();
}

但是据说不A应该简单地初始化B,因为它依赖于它,但是我们应该有一个在两个类之间有某种契约的服务。例如,如果我错了,请告诉我

所以让我们有一个界面BService

public interface BService {
    void fooB();
}

B成为DiB

public class DiB implements BService {
    @Override
    public void fooB(){
        Log.e("s", "y");
    }
}

A成为DiA

public class DiA {
    BService bService;

    public DiA(BService bService){
        this.bService = bService;
    }

    public void foo(){
        bService.fooB();
    }
}

我们可以使用Alike

public void dIdo(){
        BService service = new diB();
        diA a = new diA(service);
        a.foo();
}

所以我读到 DI 的好处是:

  1. 可测试代码:因为我实际上可以在 JUnit 中测试这两个代码(我不想在这里发布测试以避免冗长的问题)
  2. 解耦:它说如果类B发生变化,那么A不应该受到影响,我无法理解,因为如果我fooB()在类中更改BfooB2(),我将不得不更改覆盖方法,BService这反过来意味着我将不得不在类中更改它A

两种代码似乎都可以正常工作,我无法理解其中一个的好处,只是另一个更复杂。所以请你能在这个简单AB类的背景下更多地告诉我一些好处。我没有得到什么?

标签: javadependency-injection

解决方案


您不需要为它创建的接口将其归类为依赖注入。这个类使用依赖注入:

public class A {
    private final B b;

    public A(B b) {
        this.b = b;
    }

    public void foo(){
        b.fooB();
    }
}

不要想太多。当您不理解时,“依赖注入”听起来像是一个复杂的概念,但名称实际上完美而简洁地描述了该概念。让我们分解一下:

依赖性:某物所依赖的事物
注入:将外部事物放入其他事物中的行为

在上面的例子中,我们是不是把我们依赖的东西从外面放到了我们的类里面?是的,我们是,所以我们使用依赖注入。我们的类是否实现接口无关紧要。

有充分的理由说明将类实现到接口是一个好主意,但这与依赖注入无关。不要混淆这些东西,不要认为这是一个要求。


解决可测试性:是的,在您的非依赖注入版本中,我们可以测试AB. 我们不能A孤立地进行测试,B但那又如何?谁说我们愿意?这会给我们带来什么好处?

好吧,假设B不是那么微不足道。假设B从数据库中读取并返回一些值。我们不希望我们的单元测试A依赖于数据库,因为A它不关心数据库,它只关心能够fooB. 不幸的是,如果A是负责创造的人,B那么我们就无法改变这种行为。它只能做一件事,在我们的生产代码中,我们需要它来创建一个B与数据库对话的对象,所以这就是我们所坚持的。

但是,如果我们要注入依赖项,那么我们可以在真实代码中执行此操作:

new A(new DatabaseB());

并在我们的测试中注入一个“假”或“模拟” ,就像它在与数据库交谈而不实际这样做:

new A(mockB);
new A(fakeB);

这允许我们以A两种不同的方式使用:有和没有数据库;用于生产代码和测试代码。它给了我们选择的灵活性。


推荐阅读