我已经读过,明确地从DI机制请求对象实例被认为是DI / IoC的一般反模式。这是因为,当对象进入作用域时,它应该已经注入了它需要的所有依赖项。在Guice-land中,这种反模式将表示为:
Service svcImpl = (Service)injector.getInstance(Service.class);
显然,这种反模式的一个例外是引导/依赖性解析阶段,在这个阶段,你要求Guice提供所有顶级 root (“root”,因为所有其他对象都是如此)来自它的对象。
有趣的是,在详尽的在线搜索之后,我找不到任何有关此引导过程的实用代码示例!我会想象它看起来像这样:
public void bootstrap() {
RootObj1 root1 = (RootObj1)injector.getInstance(RootObj1.class);
RootObj2 root2 = (RootObj2)injector.getInstance(RootObj2.class);
this.root1 = root1;
this.root2 = root2;
// Since all objects flow from these two "root" dependencies, bootstrapping
// is complete. root1 and root2 contain all the dependencies the application
// needs from here on out, and the "injector" object is no longer needed.
// More importantly, injector is never used anywhere else in the code, and
// therefore the code is not in violation of this anti-pattern.
}
这是正确的,还是我离开这里?我问的只是因为找不到任何有用的例子!!
当我写这篇文章时,我开始猜测自己,因为这似乎不可行/实用。
这是因为,实际上应用程序的依赖关系图将是庞大的,有许多独立的,不同的“依赖树”,每个都有自己的根。这将导致某种Bootstrapper
对象的必要性,负责返回每个树的根,以便代码库中的所有其他对象可以向它们所属的“树”请求适当的根对象。这听起来非常复杂。
关于如何在现实世界中实施引导的工作代码示例可能有助于为我带来一些清晰度。提前谢谢!
答案 0 :(得分:2)
我认为你很难找到一个好榜样的原因是因为你让它变得比它需要的更复杂。引导并不比你的代码片段复杂,除了你可能需要在root1
或root2
上调用一个方法让你的应用程序开始做它做的任何事情!
其余的只是由Guice处理。在执行过程中实例化的任何对象都可以通过@Inject
带注释的构造函数(或方法)从Guice获得所需的对象。没有必要使用Boostrapper对象来控制所有树的所有根,因为DI容器管理所有实例。如果一棵树中的对象需要另一棵树中的对象,那么只需@Inject
它!无需“询问”Bootstrapper对象。对于具有ServiceLocator
背景的人来说,这有时很难设想,但它确实是设计课程的更有凝聚力的方式。
Guice有几个用于管理依赖关系图的工具。不同的依赖树通过模块进行管理,这些只是一组有凝聚力的绑定。 Guice因此鼓励您封装功能并让注入器解决相互依赖性。此外,Guice在需要之前不会实例化图形(除了可以急切加载的单例之外),并且开发人员可以使用Provider
接口和方法显式延迟实例化。
如果您解释了您希望使用Guice的应用程序类型,或者解释您习惯使用的应用程序类型,那么它可能会有所帮助。这将使我们更好地了解什么是没有意义的。