运行时数据的依赖注入:工厂和直接依赖关系

时间:2017-07-12 08:31:56

标签: java spring dependency-injection guice

我对依赖注入有一个普遍的理解问题,独立于特定的依赖注入框架。假设我有一个需要运行时参数的类:

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并使测试变得更难。

1 个答案:

答案 0 :(得分:-2)

这就是为什么你应该有控制反转容器并允许他为你做脏事。像 Spring 那样。您只需通过配置指出bean所需的依赖关系, Spring 注入此依赖关系。