When trying to show coworkers of the advantages of Dependency Injection I often encounter the argument, that it hurts one of the major object-oriented principles – encapsulation.
Let us consider the following basic example of class that has two dependencies, created in the constructor:
public class SomeClass
{
IWriter writer;
ILogger logger;
public SomeClass()
{
this.writer = new StreamWriter();
this.logger = new RegistryLogger();
}
}
Client code:
SomeClass someClass = new SomeClass();
SomeClass has direct dependencies and can’t be used without them and is clearly not testable. Let us see a implementation with dependency injection:
public class SomeClass : ISomeClass
{
IWriter writer;
ILogger logger;
public SomeClass(IWriter writer, ILogger logger)
{
this.writer = writer;
this.logger = logger;
}
}
This is clearly much better, but is considered to be violating the encapsulation principle form some developers. Encapsulation principle tells us to hide the class inner workings form the user. This is important in order to allow us to change the class implementation without changing all of its clients. This is a valid point, that I respect, we all strive to the “low maintenance road” (Ayende) - the most important thing in software development.
However let us look at the client code and see if it actually breaks the encapsulation principle:
ISomeClass someClass = Container.Resolve
What we see here is that, the client code does not even know a damn thing about the class dependencies!
We just let the dependency injection container do the heavy lifting for us and don’t worry how to create all of the class dependencies.
In practice we actually do not even have the possibility to use the constructor!
That’s true – in production code instantiating a class from the constructor would require creating all of its dependencies, which would require instantiating their dependencies and so on. It would be safe to say, that the developers can’t even use the constructor and must instantiate their objects using the dependency injection container, which is so much easier.
So the user of the code does not actually even know what kind if dependencies a class has – all of this because of the dependency injection container. So actually instead of breaking encapsulation we are driving it to a whole new level – each individual class does not get to decide what kind of object it needs – everything gets configured in the configuration of the container. This definitely does not break the encapsulation principle. It makes it hold even stronger.
As a side note I want to point out, that I am definitely against the point of view “If you let the developers to bad things, then they will”. If you don’t trust your developers you shouldn’t hire them in the first place. Treat all the of the developers as stars and they will be.
Happy dependent less programming!