【发布时间】:2017-07-12 08:31:55
【问题描述】:
我对依赖注入有一个一般的理解问题,独立于特定的依赖注入框架。假设我有一个需要运行时参数的类:
class ClassWithRuntimeDependency {
ClassWithRuntimeDependency (String myRuntimeParameter) {
//...
}
}
现在要将这个运行时参数放入我的类中,几个依赖注入框架的文档告诉我使用工厂。这个工厂接受运行时参数并用它创建一个ClassWithRunetimeDependency 的实例。
但是假设ClassWithRuntimeDependency 是一个非常基本的类,几乎所有其他类都需要它:
Class A -> Class B -> Class C -> Factory<ClassWithRuntimeDependency>.
现在我也无法创建没有这个运行时依赖的类 C,所以我需要为它创建一个工厂。但同样适用于 A 类和 B 类!这导致类 A 的工厂具有运行时依赖项,该依赖项仅在构造 ClassWithRuntimeDependency 时需要。这意味着我不会将直接依赖项注入到 A 类中,这也不是最佳实践 (github)。我知道我也可以将这种运行时依赖项引入所有需要的方法,而不是到处使用工厂,但这只会转移问题。
我这里有什么误解还是有更好的解决办法?
为了进一步表达这个问题,如果我在任何地方都使用工厂,这可能是我的 A-C 类:
// Needs a factory because of runtime parameter.
// Imho, this is the only class which should really need a factory because
// it is the only class having the direct runtime dependency, all
// others below are indirect
class ClassWithRuntimeDependency {
ClassWithRuntimeDependency (String myRuntimeParameter) {
//...
}
}
// Needs a factory because of runtime parameter in ClassWithRuntimeDependendcy
class C {
C(String myRuntimeParameter, @inject FactoryForClassWithRuntimeDependency reallyNeededFactory) {
this.withRuntimeDependency = reallyNeededFactory(myRuntimeParameter);
}
}
// Needs a factory because of runtime parameter in C -> ClassWithRuntimeDependendcy
class B {
B(String myRuntimeParameter, @inject FactoryForC cFactory) {
this.c = cFactory(myRuntimeParameter);
}
}
// Needs a factory because of runtime parameter in B -> C -> ClassWithRuntimeDependendcy
class A {
A(String myRuntimeParameter, @inject FactoryForB bFactory) {
this.b = bFactory(myRuntimeParameter);
}
}
(我没有使用特定DI框架的语法)
所以我最终得到了一个 AFactory,其依赖项只有 ClassWithRuntimeDependency 需要。当然,我也可以省略构造函数中的参数并仅使用它的方法(as suggested here),但如果我在这些类中的任何一个中有许多需要此参数的方法,这真的会炸毁我在所有依赖类中的 API ,因此只是转移了问题。
到目前为止我想出的唯一解决方案是注入一个context 对象(或context 对象的提供者),并用运行时数据填充这个上下文对象。但这也会导致temporal coupling 并使其更难测试。
【问题讨论】:
-
您可以考虑将某种运行时上下文自动装配到您的应用程序中,而不是将您的参数推送到您的类中。所以每个类都可以自己获取运行时参数。
-
你的基本假设是错误的。如here 所述,您的应用程序组件在初始化期间应该不需要运行时数据。
-
@Toni,你没有详细介绍,但你看过 Guice 的AssistedInject吗?
-
@Toni,实际上这是这种方法的一个优势。您必须模拟该上下文,Spring 会自动将其注入到您的对象中以进行测试。只要您能够轻松地模拟它们,依赖关系对于测试来说并不坏。
-
你认为这可能是this question 或this one 的欺骗吗?就我个人而言,我是前者的儿童注射器解决方案的粉丝,并且认为它会很好地适用于您的用例。
标签: java spring dependency-injection guice