0

I'm a big fan of dependency injection and working in a embedded project where dynamic allocation is not allowed. I'm always injecting dependencies in C++ in this way:

class MyCar : public ICar
{
private:
  IEngine &engine;

public:
  MyCar(IEngine _engine) : engine(_engine) { }

  /* Some other methods */
};

And somewhere else I'm composing the applicaton:

// Composition Root
main() 
{    
  // Create instances
  MyEngine engine;
  MyCar car( engine );    

  /* Other initializations and then while(1) */
}

Someone in my team saw the service locator example from this link (Service Locator on GameProgrammingPatterns and now writes for all instances a locator:

class EngineLocator
{
public:
  static IEngine& getEngine() { return static MyEngine engine; }
};

class MyCar : public ICar
{
private:
  IEngine &engine;

public:
  MyCar(/* now empty */) : engine(EngineLocator::getEngine()) { }

  /* Some other methods */
};

I think this is a bad design from a maintainability and testing standpoint:

  • The Implementation now depends on the Locator and the Interface Class IEngine. If I want to replace IEngine with a mock, I have to edit the additional Locator Class or replace it.
  • The Implementation MyCar hides it dependencies (it has a empty constructor, but the dependencies still exist)
  • In my example I have a single place (the composition root) where I instantiate all classes. With a service locator the creation is spreaded over different classes.
  • The Locator class can be misused like a global variable
  • This example Engine instance in the Locator has no constructor parameters. If there are any, then the Engine Class has to use other locators... I think this is really difficult to understand and to track.

There are different opinions about this pattern (for example M. Seemann (Dep. Injection in .NET), but maybe this is a valid approach in an embedded environment with static initialization. Maybe I'm misunderstanding something in this concept. What do you think?

pr0d1g1
  • 70
  • 5
  • 2
    This question may end up getting closed as opinion-based, but for the record, I agree with your objections. The code as presented is effectively replacing dependency injection with global variables. – dlf Jun 04 '14 at 14:55
  • This example looks like only half of the pattern. The point is to be able to replace the type of engine as needed. There needs to be separate engine objects that either register themselves or are registered as the engine service provider. Then you would be able to insert testing engines and such. – John Jun 04 '14 at 15:17
  • Thanks for your answers. John you are right, maybe it would be possible to register engine objects. That was not up to discussion, I have to think about that. – pr0d1g1 Jun 04 '14 at 15:36

0 Answers0