Let me start with a story.

Bob need a new assistant for his startup. He hired Janice. Bob wanted Janice to concentrate more on the paper work. One day Bob wanted print outs of some old invoices. Janice collected those invoices. She then get a new printer from the store and get those invoices printed. Bob was happy.

Few days later Bob wanted some of his user feed back forms to be scanned and uploaded. Janice went out and get a new scanner and get the job done. Similarly every time Bob assign a new job, Janice has to look for required materials to get the job done. Also she has to manage those inventories. Whenever the printer ran out of ink she had to fix it. She was little worried, since she was not able concentrate on her actual job. She brought the concern to Bob.

Bob thought through that and realised the problem. So he decided to provide the required materials to Janice whenever he assign a job. Janice was happy. But Bob cannot manage those materials continuously because of his busy schedule. So Bob hired Joey as admin and he wants Joey to manage all those inventories for him. So whenever Bob assign a new job to Janice Joey make sure he provide all the required materials to complete the job. All three of them now understood their responsibilities and lived happily.

Let's get to the point.


In object oriented programming, an object must depend on one or more other objects to perform a job. Consider our employee class.

public class Employee 
{
private readonly IPrinter printer;
private readonly IScanner scanner;

public Employee()
{
this.printer = new BlackWhitePrinter();
this.scanner = new Scanner();
}

public void GetInvoices()
{
// Get invoices.
this.printer.Print(invoices);
}

public void UploadFeedbacks()
{
this.scanner.Scan(feedbacks);
// Upload feedbacks to database
}
}

It needs to perform certain functions for which it has to depend on certain other low level objects. For example, to hand over few old invoices to Bob Janice has to depend on a printer. The employee class is creating and managing it's own dependencies. This approach has several disadvantages.

  1. Whenever the dependencies get modified, the objects depend on them are also likely to be changed. What if the constructor of the class BlackWhitePrinter changed to accept parameters.

  2. Whenever we create an object for the employee class it comes with black and white printer by default. What if in another context we need a color printer.

  3. The employee class is not focusing on its core job. Instead it is also focusing on managing dependencies, thereby increasing complexity of the class.

  4. Mocking dependencies are not possible and unit testing becomes a pain.

Dependency injection is the technique of supplying the required dependencies to an object from outside.

Let's refactor our employee class to adapt dependency injection technique.

public class Employee 
{
private readonly IPrinter printer;
private readonly IScanner scanner;

public Employee(IPrinter printer, IScanner scanner)
{
this.printer = printer;
this.scanner = scanner;
}

public void GetInvoices()
{
// Get invoices.
this.printer.Print(invoices);
}

public void UploadFeedbacks()
{
this.scanner.Scan(feedbacks);
// Upload feedbacks to database
}
}

Instead of creating the printer and scanner dependencies by itself, now the employee get those objects through constructor.

var printer = new BlackWhitePrinter();
var scanner = new Scanner();

var employee = new Employee(printer, scanner);
employee.GetInvoices();

The caller has to supply the dependencies, whenever it creates the employee object. The control over the dependencies has been shifted from the employee class to outside.

By doing this we eliminate all the disadvantages we listed earlier.

Any change to the dependencies doesn't affect the employee class. The employee class depends on the interface and not on the implementation. So a different type of printer can be injected to employee class. Employee class doesn't need to focus on managing dependencies anymore. Its responsibility is clearly defined. Unit testing employee class is now simple, since mock implementations can be supplied.

The code can be further refactored by delegating the dependency management to an external framework. (Now it's time to hire our Joey to manage all our inventories.)

Popular DI frameworks for .NET

1. Unity2. Autofac3. Ninject

For Java

1. Dagger2. Spring

I am not going to explain the API details of every framework. You can go through the links above to understand that. If we using unity framework this is how to register the dependencies and resolve objects.

IUnityContainer container = new UnityContainer();

container.RegisterType();
container.RegisterType();

var employee = container.Resolve();
employee.GetInvoices();

When you resolve an object using DI container, it will make sure that it create and supply all the dependencies to the object. So the caller and the employee class does not have to worry about the dependencies. This helps to build system with loosely coupled components.

Thanks for reading.