简体   繁体   中英

Dependency Injection with runtime data: Factories and direct dependencies

I have a general understanding problem with dependency injection, independent of a specific dependency injection framework. Let's say I have a class which needs a runtime parameter:

class ClassWithRuntimeDependency {
  ClassWithRuntimeDependency (String myRuntimeParameter) {
    //...
  }
}

Now to get this runtime parameter into my class, documentations of several dependency injection frameworks tell me to use a factory. This factory takes the runtime parameter and creates an instance of ClassWithRunetimeDependency with it.

But let's say this ClassWithRuntimeDependency is kind of a very basic class which is needed by nearly all other classes: Class A -> Class B -> Class C -> Factory<ClassWithRuntimeDependency> .

Now I cannot create class C without this runtime dependency either, so I need to make a factory for it. But the same applies to classes A and B! This leads to a factory for class A with a runtime dependency which is only needed for constructing ClassWithRuntimeDependency . This means I do not inject a direct dependency into class A, which isn't best practice either ( github ). Instead of using factories everywhere, I know I could also introduce this runtime dependency to all needed methods, but this only shifts the problem.

Do I have a misunderstanding here or is there any better solution to this?


To further express the problem, this could be my classes AC if I would have used factories everywhere:

// 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);
  }
}

(I did not use the syntax of a specific DI framework)

So I end up having an AFactory with a dependency that is only needed by ClassWithRuntimeDependency . Of course, I could also leave out the parameter in the constructor and use it methods only ( as suggested here ), but if I have in any of these classes many methods which needs this parameter, this really blows up my API in all dependent classes, therefore kind of only shifts the problem.

The only solution I came up so far is to inject a context object (or a provider of a context object), and fill this context object with runtime data. But this also leads to temporal coupling and makes it harder to test.

This is why you should have Inversion of Control container and allow him to do dirty work for you. Like Spring does. You just point what kind of dependency you need for your bean through configuration and Spring inject this dependency.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM