Why is the link with new keyword dependencies considered bad?
I've been using Dependency Injection for a while now, and now I want to talk about IoC and DI with a group of new developers. I remember explaining this to one guy in person and he asked me:
"Why not just use:
private IMyInterface _instance = new MyImplementaion();
instead of going through all the DI alarm. "
My answer is "Testing modules requires mocks and stubs." - but we don't write unit tests at my company so that he doesn't convince him. I told him that the concrete implementation is bad as you are closely related to one implementation. Changing one component will change the other.
Can you provide an example for such code? Can you give me more reasons why this code is bad?
It seems so obvious to me that it's hard for me to explain it :-)
source to share
Problem with next link
public class MyClass
{
private IMyInterface _instance = new MyImplementation();
...
Means that at any time it MyClass
is created (either directly or via an IoC container) that it will always immediately create a specific one MyImplementation
and associate its dependency _instance
with that specific implementation. In turn, it is likely that it MyImplementation
has other dependencies that are also linked in this way.
The advantages of decoupling such classes, which MyClass
only depends on the interfaces to its dependencies, and not on specific implementations of the dependencies (i.e. on D SOLID ):
-
for unit testing. As you mentioned, for testing
MyClass
in isolation, with dependenciesnew'ed
, you need to do nasty things likeMoles / Fakes
mocking a hard-wired dependencyMyImplementation
. -
for substitution - by connecting only to the interface, you can now change various concrete implementations
IMyInterface
(for example, via the strategy pattern) without changing the code inMyClass
. -
in order to make the dependencies clear and obvious on your system, as a dependency
IMyInterface
may have additional dependencies that need to be resolved (and may also need tweaking). IfMyClass
hides an internal dependencyIMyInterface
, the caller doesn't see what the dependency isMyClass
. While this was common in classic 1990 OO (i.e. Encapsulation + Composition), it can overshadow the implementation as deploying all dependencies still needs to be done. However, when the connection is done at the interface level (i.e. MyClass users will only do this throughIMyClass
), the connection visibility interfaceIMyClass
will hide the dependency on againIMyInterface
, since the constructors are not visible on the interface). -
for configurable dependency lifetime management. By entering
IMyInterface
instead of the new oneMyImplementation
, you allow additional configuration options with regard to managing the object's lifetimeMyImplementation
. When the initial solid creationMyImplementation
was completedMyClass
, it actually took charge of theMyImplementation
lifespan. By leaving this in the IoC container, you can now play with otherMyImplementation
lifespan options that might be more efficient, for example. if the instancesMyImplementation
are thread safe, you can, for example, select an instance for multiple instancesMyClass
.
In a nutshell, this is how I believe the refactoring should look suitable for IoC constructor dependency injection:
public class MyClass
{
// Coupled onto the the interface. Dependency can be mocked, and substituted
private readonly IMyInterface _instance;
public MyClass(IMyInterface instance)
{
_instance = instance;
}
...
Bootstrapping the IoC container will define the WHICH implementation IMyInterface
to be linked and will also define the lifetime of the dependency, for example. in Ninject:
Bind<IMyInterface>()
.To<SomeConcreteDependency>() // Which implements IMyInterface
.InSingletonScope();
source to share