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?