Generally speaking, my dependencies are abstracted to interfaces, but I will only be using one concrete implementation during non-testing use. For example, were I to write a FooService
:
public class FooService : IFooService
{
private readonly IBarDependency _barDependency;
public FooService(IBarDependency barDependency)
{
this._barDependency = barDependency;
}
public FooService() : this (new BarDependency())
{
// nothing to do here
}
. . . // code goes here
}
Now purists tend to gasp in horror, because I instantiated a concrete class in the parameterless constructor. I have, in the past, shrugged this off, because I know the only time I will not be using the concrete class is when I am unit testing and mocking dependencies.
While it does couple the FooService
class to the BarDependency
class, it's not a tight coupling; these classes and interfaces also exist in the same assembly, so it doesn't seem to me like I'm losing a whole lot here, or painting myself into a corner. I can still easily test the FooService
class without getting unmanageable code, just by using the constructor that allows me to pass in mocked interfaces.
So the question is: what is actually at risk here? What am I losing with this sort of pattern that is worth adding an IoC container?
Lifetime management, for example. Maybe you use BarDependency
throughout your code and only want one instance to be alive. You can't do this if every user creates their own instances.
You also have to find all usages of new BarDependency()
if you ever want to replace it with new NewBarDependency()
.
A container fixes both problems for you, as then you configure the instantiation and lifecycle of objects in one method, namely where you set up your container.
It depends, but if the FooService needs to be accessed by some other developer, the dependency to BarDependency will be basically hidden. In my opinion not only mocking and testing is the reason for using dependency injection, but also a clear indication what is used by certaing classes, and what they are need to work properly. And maybe I'm to much purist, but when such pattern is ok, then it's easily to go further and end up with a totally tightly coupled and hard maintanable code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With