2016-07-04 100 views
1

在下面的代码(使用吉斯和依赖注入):使用依赖注入优于新的优点是什么?

public class Main { 

public static class Foo { 
    private FooInterface anInterface; 

    @Inject 
    Foo(FooInterface anInterface) { 
     this.anInterface = anInterface; 
    } 

    public void talk() { 
     anInterface.talk(); 
    } 

} 

interface FooInterface { 
    void talk(); 
} 

static class English implements FooInterface { 

    @Override 
    public void talk() { 
     System.out.println("Hello"); 
    } 
} 

static class Spanish implements FooInterface { 

    @Override 
    public void talk() { 
     System.out.println("Hola"); 
    } 
} 

public static class Module extends AbstractModule { 
    @Override 
    protected void configure() { 
     bind(FooInterface.class).to(English.class); 
    } 

} 

public static void main(String[] args) { 
    Injector injector = Guice.createInjector(new Module()); 
    Foo injectorInstanceFoo = injector.getInstance(Foo.class); 
    injectorInstanceFoo.talk(); 

    Foo regularInstanceFoo = new Foo(new Spanish()); 
    regularInstanceFoo.talk(); 

} 
} 

什么是使用Guice(injectorInstanceFoo)在“直接”的方式(regularInstanceFoo)获得的Foo实例的优势在哪里?

+1

好处是您不必自己创建'Foo',这需要您将'FooInterface'实例放到需要构建它的地方。你的'Foo'的消费者可能被深埋在你的程序中。如果您手动执行DI,则必须通过层和代码层传递它。 –

+0

但是,如果我只是在每个实例上使用** new **作为FooInterface,那么没有优势? –

+0

@BobSacamano通常你注入的类也有依赖关系,所以你不能只使用'new'。此外,如果您使用注入,您可以使用“接缝”来测试或注入不同的实现 – NamshubWriter

回答

1

让我们来谈谈使用玩具代码的程序可能是什么样的。假设它是一个控制台应用程序,并且在绘制开始屏幕时需要talk()方法。在您的设置中,您可以控制英语或西班牙语实例是绑定的(使用不同的模块; 不使用条件逻辑内部模块)。使用依赖注入的第一个优点是您的逻辑可以轻松控制代码中其他地方提供的语言,因此调用者不必都有逻辑来选择他们想要的实现。

它也使得单元测试更容易 - 我将在这里进一步深入说明:您想编写一些测试代码来测试为您的登录屏幕创建消息的行为。在LoginScreen这个类,你@Inject不同FooInstance根据您的区域化设置:

public class LoginScreen { 
    private final String message; 

    @Inject 
    public LoginScreen(FooInstance foo) { 
     foo.talk(); 
     // use other methods on foo that you didn't write 
     // 
    } 
} 

现在,你想测试LoginScreen行为 - FooInstance或其实现的行为。该语法使用JUnit和的Mockito(为简洁起见),但它是相当自我解释:

public class LoginScreenTest() { 
    @Test 
    public void testMessage() { 
     FooInstance foo = mock(FooInstance.class); 
     LoginScreen screen = new LoginScreen(foo); 
     verify(foo).talk(); 
    } 
} 

在这种情况下,我不在乎FooInstanceEnglishSpanish。我相信这些类已经正确实现了(我会在另一个单元测试中为他们写一个测试)。 合同FooInstancetalk()会写一个问候到控制台 - 我所关心的是LoginScreen抓住了这个问候,但我不在乎FooInstance表现正确。

在您的示例中,这不是超有意义的,因为我可以拨打FooInstance foo = new English();。但是,如果不是System.out.println()FooInstance必须加载数据库呢?或者如果它弹出一个Swing对话框呢?或者,如果FooInstance有其他依赖关系?在所有这三种情况下,在您的测试中拨打new English()会很痛苦。

注意:这不是区域化的最佳方式,但我只是用你的例子来运行。

相关问题