在以下代码中(使用Guice和Dependency Injection):
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)
获取Foo
的实例超过"直接"有什么好处?方式(regularInstanceFoo)
?
答案 0 :(得分: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
//
}
}
现在,您要测试 <{em> LoginScreen
的行为 - 不 FooInstance
或其实现的行为。这个语法使用JUnit和Mockito(为了简洁),但它是相当自我解释的:
public class LoginScreenTest() {
@Test
public void testMessage() {
FooInstance foo = mock(FooInstance.class);
LoginScreen screen = new LoginScreen(foo);
verify(foo).talk();
}
}
在这种情况下,我不关心FooInstance
是English
还是Spanish
。我相信这些类已经正确实现(我会在不同的单元测试中为它们编写测试)。 FooInstance
的合同是talk()
会向控制台写一个问候语 - 所有我关心的是LoginScreen
抓住了这个问候语,但我没有&#39关心FooInstance
表现正确。
这在您的示例中并不是非常有意义,因为我可以调用FooInstance foo = new English();
。但是,如果代替System.out.println()
,FooInstance
必须加载数据库呢?或者如果它弹出一个Swing对话框怎么办?或者如果FooInstance
有其他依赖项怎么办?在所有这三种情况下,在测试中调用new English()
会非常痛苦。
注意:这不是区域化的最佳方式,但我只是运行您的示例。