我(我想)理解依赖注入的目的,但我只是不明白为什么我需要Guice这样做(好吧,显然我不需要需要 Guice,但是我的意思是为什么使用它是有益的)。假设我已经存在(非Guice)代码,就像这样:
public SomeBarFooerImplementation(Foo foo, Bar bar) {
this.foo = foo;
this.bar = bar;
}
public void fooThatBar() {
foo.fooify(bar);
}
在某个更高级别,也许在我的主要()中,我有:
public static void main(String[] args) {
Foo foo = new SomeFooImplementation();
Bar bar = new SomeBarImplementation();
BarFooer barFooer = new SomeBarFooerImplementation(foo, bar);
barFooer.fooThatBar();
}
现在我基本上得到了依赖注入的好处,对吧?更容易测试等等?当然,如果你想要,你可以轻松地更改main()以从配置而不是硬编码中获取实现类名。
据我所知,要在Guice中做同样的事情,我会做类似的事情:
public SomeModule extends AbstractModule {
@Override
protected void configure() {
bind(Foo.class).to(SomeFooImplementation.class);
bind(Bar.class).to(SomeBarImplementation.class);
bind(BarFooer.class).to(SomeBarFooerImplementation.class);
}
}
@Inject
public SomeBarFooerImplementation(Foo foo, Bar, bar) {
this.foo = foo;
this.bar = bar;
}
public static void main(String[] args) {
Injector injector = Guice.createInjector(new SomeModule());
Foo foo = injector.getInstance(Foo.class);
barFooer.fooThatBar();
}
是吗?在我看来,这只是语法糖,而不是特别有用的语法糖。如果将“新的XxxImplementation()”内容分解为一个单独的模块而不是直接在main()中进行操作有一些优势,那么无论如何都可以轻松完成。
所以我觉得我错过了一些非常基本的东西。你能否告诉我Guice方式如何有利?
提前致谢。
答案 0 :(得分:20)
在现实生活和更大的应用程序中,组件的级别不仅仅是2(如您的示例所示)。它可能是10或更多。需求和依赖性也可以随心所欲地改变。
当手工执行“DI”时,这意味着您必须手动更改所有组件及其传递依赖项的所有路径。这可能只是一些工作。
使用“真正的DI”(即Guice,Spring,CDI),您只需更改一个或两个受影响的组件和接线(Guice上的Module
)就可以了。
另外:想象一下,您的一些深层嵌套组件位于工厂中,应由其他组件调用。在Guice中你只需注入一个Provider<Foo>
就可以了。手动完成时,必须在整个代码中拖动工厂及其实例的依赖关系。
这更令人沮丧。
编辑澄清最后一点:图片你有一些深层嵌套的逻辑(10级或更多级别)。在底部,您的逻辑应基于某些值创建工厂,例如实际温度:如果“暖”,则需要Cooler
,如果是“冷”,则为Heater
。两者都有接口TemperatureAdjustor
。 Cooler
和Heater
都需要很多不同的依赖关系才能完成工作。
由于因子的实例类型无法在main
中创建,因此请将其移至需要的位置。因此,您最终将两个工厂的依赖关系下移到需要它们的位置。 (“很多依赖”加上“很多依赖”是“太多不能保持理智”)
使用像Guice这样的“真正的DI”,你可以使用AssistedInject
来避免依赖的混乱,只给出工厂的实际业务价值(这里是:温度)并完成。工厂的接线在模块中完成。
答案 1 :(得分:2)
手写的DI是真正的DI。
当您考虑IOC容器的复杂性时,您必须更深入地了解为什么要使用它。我很长一段时间都是反IOC,能够设计和实现干净,快速,整洁的手工编码,真正的DI。但我对容器的想法感到满意,因为它们有助于标准化实现,并提供更基于配置的机制,用于向依赖方程式添加新的决策。其他人已经为你写了这些内容,所以你不必花时间手工编码。
许多人说要在大型应用程序中使用容器,在小型应用程序中使用手动代码。我说的恰恰相反。小应用程序的性能不受限制。了解使用打包容器的实现速度。在大型应用程序中,您将花费大量时间进行优化,请考虑对DI进行手动编码。
编辑:但是我要补充一点,IOC容器或手工编码,总是使用DI和代码到界面 - 无论你正在使用多么简单的应用程序。即使在小应用程序中也可以编写出色的代码。