How do I supply an object to a parent constructor when that object is normally is dependency injected?

35 views Asked by At

Suppose I have these made-up classes (I know nothing about cars btw)

@Singleton
class ElectricEngine implements Engine {
}

class Vehicle {
  private final Engine engine;
  Vehicle(Engine engine, SteeringSystem ss, ...) {
    this.engine = engine;
  }
}

Normally, child classes would be built in this way

class Tesla extends Vehicle {
  @Inject
  Tesla(ElectricEngine engine, SteeringSystem ss) {
    super(engine, ss);
  }
}

What I'd like to do not have the child specify the Engine and have a class such as

class ElectricVehicle extends Vehicle {
  ElectricVehicle(SteeringSystem ss) {
   super(electricEngine???, ss);
  }
}

class Tesla extends ElectricVehicle {
  @Injected
  Tesla(SteerByWireSystem ss) {
    super(ss);
  }
}

The question is, how can ElectricVehicle get the ElectricEngine object to pass to its parent?

I considered doing field injection but not sure if that would solve it and also not a fan of it based on this.

Any ideas?

1

There are 1 answers

3
DarkMatter On BEST ANSWER

If you want to use the Injection to handle your bean, you'll need to inject something.

An alternative, pure Java, solution to a singleton is to have the class hold it's own singleton instance:

class ElectricEngine implements Engine {
    private static ElectricEngine instance;

    public static ElectricEngine getElectricEngine() {
        if(instance == null) {
            instance = new ElectricEngine();
        }
        return instance;
    }
}

class Tesla extends ElectricVehicle {
  @Injected
  Tesla(SteerByWireSystem ss) {
    super(ElectricEngine.getElectricEngine(), ss);
  }
}

Additional ideas based on authors comment. Reverting to Spring because it's what I know best.

I would probably go for something like this:

class Tesla extends ElectricVehicle {
    @Autowired
    Tesla(ElectricEngine electricEngine, SteerByWireSystem ss) {
        super(electricEngine, ss);
    }
}

@Component
class TeslaFactory {
    private final ElectricEngine electricEngine;
    
    @Auwotired
    public TeslaFactory(ElectricEngine electricEngine) {
        this.electricEngine = electricEngine;
    }
    
    @Bean
    public Tesla newTesla(SteerByWireSystem ss) {
        return new Tesla(electricEngine, ss);
    }
}

In general, I prefer the more controlled way of creating beans via methods rather than deferring it to the injection framework.