0

When an object creation depends on other objects, it is better to have those objects injected into the constructor of the first object's class (dependency injection). For example: Car car1 = new Car(new Body("body1"), new Motor("motor1"), ...).

Instead of having them created into the class' constructors:

class Car {
  Car(String s1, String s2) {
    this.body = new Body(s1);
    this.motor = new Motor(s2);
  }
}

But what if those parameters depend on each other?

5
  • 1
    That's one of the things a 'factory" solves: it is a thing that encapsulates the idea of "how do you construct something" especially when that something to construct is complex to construct, has dependencies on other things, may have options/subtypes/etc that have to be chosen at run-time.
    – davidbak
    Nov 14, 2021 at 17:47
  • @davidbak Thanks for your response, did you mean "factory pattern"?
    – X Y
    Nov 14, 2021 at 18:25
  • 1
    Yes, these days more commonly and concisely called, "a factory"
    – davidbak
    Nov 14, 2021 at 18:26
  • 1
    There are several different "factory patterns"; when people say "factory", it's either a static (or free) function that creates other objects, or in this case, an object that can be instantiated, that allows you to create other objects; see my answer below. (A factory object is either an ordinary object, or an object that represents a function - something like a lambda, delegate, function pointer, etc., that you can pass around.) Nov 14, 2021 at 18:31
  • 1
    Could you edit your code to show how your parameters "depend on each other" and how you would construct them if you weren't using DI? Nov 14, 2021 at 18:54

1 Answer 1

4

You use dependency injection in order to allow something else (some calling code) to choose the concrete implementation of the dependencies; your class can then call the methods provided by the abstract interface(s) to do its logic. The actual mechanism by which the injection happens is of secondary importance - sometimes it's done through a dependency injection container, and sometimes it's done manually (e.g., in a unit test).

One way to deal with this is to break the circular dependency by introducing an intermediate object - a factory. A factory is just an object that provides abstract methods for creating other objects. It's useful when you need to supply parameters that aren't known or available at creation time; instead of creating the object itself you create a factory instance, and save it for later, when the needed information becomes available.

Car <--> Body & Car <--> Motor Interdependencies

Suppose your Body and Motor classes need the Car instance as a parameter. Instead of having the Car depend on Body and Motor directly, have the Car depend on a factory object (or a method/lambda) that can supply a Body instance and a Motor instance on demand.

The factory can have different forms - it can be a class that has CreateBody and CreateMotor methods, or it can be two separate lambdas, one for each dependency. Or it could be some combination of the two, or it could maybe use reflection - that's all up to you.

It might not be immediately clear what's the difference compared to just calling a constructor directly, but note that the factory is a separate object that doesn't need the Car for its own construction; it just allows you to pass a car instance to its creator methods. Since it's an abstraction, you can provide a different factory that supplies different car parts when you need to.

class Car {
  private IBody body;
  private IMotor motor;

  // You can create & inject an ICarPartFactory implementation
  // as its construction doesn't need a previously existing Car instance
  public Car(ICarPartFactory carPartFactory) {
    this.body = carPartFactory.CreateBody(this);
    this.motor = carPartFactory.CreateMotor(this);
  }
}

The CreateBody and CreateMotor methods just invoke the appropriate constructor directly:

public IBody CreateBody(Car car) {

  // Note that it creates a concrete Body, 
  // but returns the abstract IBody type
  return new Body(car);    

  // Some other factory implementation might return 
  // a ReenforcedBody, or a RustyBody, or something else
}

To supply a different set of car part implementations (different concrete part classes), you implement a different factory (or supply a different set of lambdas, or whatever). Again, you can either register the factory into a DI container, or inject it manually, depending on the circumstances.

This way, you avoid creating "half-made" car part objects that you might accidentally use before they are in a consistent state (e.g., in a design where, say, the Motor has the default parameterless constructor, and a method to set the car after the motor instance is created, you might forget to call the SetCar method, making your code broken, and if the circumstances conspire, you might not discover such a bug until much later).


Another way you could approach this is to reconsider the design itself. Think about what your code actually needs to do, and if you really need to pass the car instance to the constructors of the car parts. Sometimes, that'll be the case, but other times, it'll turn out that you don't really need to - maybe the car parts only need very specific data or callbacks that you can supply through their methods. If that makes more sense and makes the overall code simpler in some way, maybe go for that.


Body <--> Motor Interdependency

You could, in principle, use the same trick to break the dependency; you could pick one object to be the more "dominant one", e.g. Body, and inject a MotorFactory. If you mentally remove Car from the picture, and just focus on the two parts, it's basically the same situation, the same dependency structure.

But, the question is: should you? If in your design the Car and the Body depend one each other, and the Car and the Motor depend on each other, and the Body and the Motor depend on each other - then you might have a bigger problem on your hands. This is more of a problem is this is code that is to evolve and require maintenance over time, and not a one-off project.

// Works, BUT maybe there's a better approach
// Suggestion: Rethink the design

class Car {
  public Car(ICarBodyFactory carBodyFactory) { /*...*/ }
}

class Body : IBody {
  public Body(/* Car car */, ICarMotorFactory carMotorFactory) { /*...*/ }
}

What we strive to do is to limit interdependencies between things as much as possible (to limit which code "knows" about which other code), because the more of these interconnections there are, the more of a hard-to-maintain spaghetti mess the code will become over time. So your first instinct in such a situation, where all these objects depend on each other, is treat it as a "code smell" - an indication that you should rethink the design, and maybe find a better way to do it.

For example, since both these objects are member fields of the Car class, the car class can orchestrate their interaction (it can control what they do and communicate, and pass data between them - indeed, that's probably one of its main jobs), which means that Body and Motor could very likely work together towards a common goal, without ever knowing about each other. Think of the Body and Motor classes as being two separate departments in a company, with the Car class being in a managerial role, facilitating communication between the two, delegating tasks, etc.

2
  • Thanks for your great and detailed answer, but suppose that "body" and "motor" depend on each other, can "factory" solve that?
    – X Y
    Nov 14, 2021 at 18:39
  • 2
    @XY - edited the answer, hope this clears things up Nov 14, 2021 at 19:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.