Is this dependency injection?

Viewed 209

Is this dependency injection if I change the below code

class Needer
{
    Needed obj;
    AnotherNeeded obj2;

    public Needer()
    {
        obj = new Neede();
        obj2 = new AnotherNeede();
    }
}

To this code

class Needer
{
    Needed obj;
    AnotherNeeded obj2;

    public Needer(Needed param1, AnotherNeeded param2)
    {
        obj = param1;
        obj2 = param2;
    }
}
4 Answers

The first option is tightly coupling the dependent class to its dependencies by newing them up in the constructor. This makes testing that class in isolation very difficult (, but not impossible).

The second option follows what is sometimes referred to as the The Explicit Dependencies Principle

The Explicit Dependencies Principle states:

Methods and classes should explicitly require (typically through method parameters or constructor parameters) any collaborating objects they need in order to function correctly.

The said, it is also usually advised to have dependent classes depend on abstractions and not concretions or implementation concerns.

So assuming that those needed classes have interfaces/abstractions that they derive from it would look like

class Needer {
    private readonly INeeded obj;
    private readonly IAnotherNeeded obj2;

    public Needer(INeeded param1, IAnotherNeeded param2) {
        obj = param1;
        obj2 = param2;
    }

    //...
}

The allows more flexibility with the dependent class as it decouples it from implementation concerns, which allows the class to be tested in isolation easier.

Robert C. Martin described Dependency Injecton in his SOLID design proposal. It basically states that:

  • High-level modules should not depend on low-level modules. Both should depend on abstractions.

  • Abstractions should not depend on details. Details should depend on abstractions.

Notice a word being used a lot in that description? "Abstraction".

You get part of the problem right in your second example, you no longer manually instantiate instances of the class, you instead pass them through the constructor. This leads into a new potential problem though, what if you need a different implementation of some class (e.g a "mock" and "real" services). If your constructor took the abstractions instead of the concretes you could change the implementations in your IoC configuration.

Any sort of service or functional class should typically have an abstraction behind it. This allows your code to be more flexible, extendable and easier to maintain. So to make your second example use true dependency injection:

class Needer
{
    public INeeded obj { get; set; }
    public IAnotherNeeded obj2 { get; set; }

    public Needer(INeeded param1, IAnotherNeeded param2)
    {
        obj = param1;
        obj2 = param2;
    }
}

Now you can have all sorts of implementations:

public class MockNeeded : INeeded

public class ApiNeeded : INeeded

etc, etc

the second example is DI (dependency injection). DI is usually used with IoC (Inversion of Control) which takes care of creating the dependencies for you based on some configuration. have a look at autofac. autofac

The injection doesn't happen on it's own.

Instead, there should be some kind of a factory that generates objects and uses a dependency resolver, if available.

For instance, an MVC.NET framework is that kind of a "factory", when it creates an instance of, let's say, a Controller class, it uses the DependencyResolver.Current property to populate the constructor arguments.

Related