Click here to Skip to main content
Click here to Skip to main content

Dependency Inversion Principle, IoC Container, and Dependency Injection (Part - 1)

, 6 Jun 2014
Rate this:
Please Sign up or sign in to vote.
This is the first part of article on Dependency Injection. It will give you an idea about what Dependency Inversion Principle is. There are other two parts of the article which explain how to implement DIP.

Introduction  

While working on a WPF application, I came across such kind of terms like Unity Container, IoC, Dependency Injection. At that time I was in a confusion, thinking of the need of all these. But later on when I gradually knew about the benefits, I realized the actual need of it.

In this article I will try to explain the need and usage of DI and IoC. Basically this article is divided into three parts:

This part of the article is about Dependency Inversion Principle. Hope you will find this article easy to understand and implement.

Prerequisites 

Better to have little knowledge on following items: 

  • Open/closed principle
  • Interface Segregation principle 

Dependency Inversion Principle (DIP)

DIP is one of the SOLID principle, which was proposed by Sir Robert Martin C. in the year of 1992.

According to C. Robert Martin's Dependency Inversion Principle :   

  1. High-level modules should not depend on low-level modules. Both should depend on abstractions.
  2. Abstractions should not depend upon details. Details should depend upon abstractions.

DIP refers to inverting the conventional dependency from high-level-module to low-level-module.

Example from Bob Martin Peper journal:  

In Figure-1.a copy program (high-level module) which reads from keyboard and writes to printer. Here the copy program is depending on Read Keyboard and Write Printer and tightly coupled.

public class Copy
{
    public void DoWork()
    {
        ReadKeyboard reader = new ReadKeyboard();
        WritePrinter writer = new WritePrinter();

        string data = reader.ReadFromKeyboard();
        writer.WriteToPrinter(data);
    }
}

This implementation seems perfectly fine until we have a requirement of adding more reader or writer to the program. In that case we need to change the copy program to accommodate new readers and writers and need to write a conditional statement which will choose reader and writer based on the use, which violates Open/Close principle of object oriented design. 

For example we want to extend copy program (see figure 1.b) which also can read from scanner and write to flash disk. In such case we need to modify our copy program:

public class Copy
{
    public void DoWork()
    {
        string data;
        switch (readerType)
        {
            case  "keyboard":
                ReadKeyboard reader = new ReadKeyboard();
                data = reader.ReadFromKeyboard();
                break;
            case "scanner":
                ReadScanner reader2 = new ReadScanner();
                data = reader2.ReadFromScanner();
                break;
        }
        switch (writerType)
        {
            case "printer":
                WritePrinter writer = new WritePrinter();
                writer.WriteToPrinter(data);
                break;
            case "flashdisk":
                WriteFlashDisk writer2 = new WriteFlashDisk();
                writer2.WriteToFlashDisk(data);
                break;
        }
    }
}

Similarly if you keep on adding more reader or writer we need to change the implementation of copy program as copy program is depending on implementation of reader and writer.   

To resolve this problem we can modify our copy program to depend on abstractions rather depending on the implementation. The following figure explains about inverting the dependency.

In above figure Copy program is depending on two abstractions IReader and IWriter to execute. As long as low level components confirms to the abstractions, copy program can read from those components.

Example, in the above figure ReadKeyboard implements IReader interface and WritePrinter implements IWriter, hence using IReader and IWriter interface copy program can perform copy operation. So if we need to add more low level components such as scanner and flash disk, we can do by implementing from scanner and flash disk. The following code illustrates the scenario: 

public interface IReader
{
    string Read();
}

public interface IWriter
{
    void Write();
}

public class ReadKeyboard : IReader
{
    public string Read()
    {
        // code to read from keyboard and return as string
    }
}

public class ReadScanner : IReader
{
    public string Read()
    {
        // code to read from scanner and return as string
    }
}

public class WritePrinter : IWriter
{
    public void Write(string data)
    {
        // code to write to the printer
    }
}

public class WriteFlashDisk : IWriter
{
    public void Write(string data)
    {
        // code to write to the flash disk
    }
}

public class Copy
{
    private string _readerType;
    private string _writerType;

    public Copy(string readerType, string writerType)
    {
        _readerType = readerType;
        _writerType = writerType;
    }

    public void DoWork()
    {
        IReader reader;
        IWriter writer;
        string data;
        switch (readerType)
        {
            case  "keyboard":
                reader = new ReadKeyboard();
                break;
            case "scanner":
                reader = new ReadScanner();
                break;
        }

        switch (writerType)
        {
            case "printer":
                writer = new WritePrinter();
                break;
            case "flashdisk":
                writer = new WriteFlashDisk();
                break;
        }

        data = reader.Read();
        writer.Write(data);
    }
}

In this case details are depending on abstractions but still high-level class is depending on low-level modules. As we are instantiating low-level module object in the scope of high-level module. Hence high-level module still needs modification on addition of new low-level components, which doesn't fully satisfy DIP. 

In order to remove the dependency, we need to create the dependency object (low-level component) outside of high-level module, and there should be some mechanism to pass the that dependency object to depending module.   

Now a new question arises, how can we implement Dependency Inversion.  

 

One of the answer to the above question can be Inversion of Control (IoC). Consider the following code segment:  

public class Copy
{
    public void DoWork()
    {
        IReader reader = serviceLocator.GetReader();
        IWriter writer = serviceLocator.GetWriter();
        string data = reader.Read();
        writer.Write(data);
    }
}

The highlighted code replaces the logic to instantiate reader and writer object. Here we are inverting the control creation from Copy program (high-level module) to service locator. Hence the copy program need not to be changed with any addition/removal of low-level module.

Dependency Injection is one of the mechanism to implement IoC. In the next parts of this article I will be covering what is an Inversion of Control (IoC), and the way to implement the Dependency Inversion Principle using different mechanism (Dependency Injection (DI) is one of the implementation).

Summary

In this part of the article I have explained Dependency Inversion Principle (DIP), and its need in the real time scenario.

In the later part of the article I will explain Inversion of Control (IoC) and Dependency Injection (DI).

History   

  • First revision : 12-March-2013

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Chinmaya_Champatiray
Software Developer (Senior) PAREXEL International
India India
I have been working in IT industry since last 4.5+ years. Currently working as a Senior Software Engineer in PAREXEL International.
 
I always strive to know about new things in .NET. Always want to keep myself busy.
 
Life is short. So enjoy each and every moment of life. Keep smiling. Smile | :)

Comments and Discussions

 
QuestionCorrect function implementation? PinmemberRudolf Grauberger1-May-14 2:35 
AnswerRe: Correct function implementation? PinpremiumChinmaya_Champatiray6-Jun-14 4:47 
QuestionIoC - real or imagined? Pinmemberrrotstein11-Feb-14 9:11 
AnswerRe: IoC - real or imagined? PinmemberChinmaya_Champatiray11-Feb-14 17:15 
GeneralMy vote of 5 Pinprofessional@AmitGajjar16-May-13 6:37 
GeneralRe: My vote of 5 PinprofessionalChinmaya_Champatiray16-May-13 8:03 
Thanks Amit. Smile | :)
GeneralExcellent presentation - couple small typos Pinmembertiredoldcoder24-Apr-13 22:49 
GeneralRe: Excellent presentation - couple small typos PinprofessionalChinmaya_Champatiray24-Apr-13 23:31 
GeneralMy vote of 5 PinmemberMember 865734524-Apr-13 5:39 
GeneralRe: My vote of 5 PinprofessionalChinmaya_Champatiray24-Apr-13 6:41 
GeneralMy vote of 5 PinmemberPatrick Skelton22-Apr-13 22:25 
GeneralRe: My vote of 5 PinprofessionalChinmaya_Champatiray22-Apr-13 22:42 
GeneralMy vote of 5 Pinmembermariuszkiler21-Apr-13 7:50 
GeneralRe: My vote of 5 PinprofessionalChinmaya_Champatiray22-Apr-13 22:42 
GeneralMy vote of 5 PinmemberGregoryW16-Apr-13 1:54 
GeneralRe: My vote of 5 PinmemberChinmaya_Champatiray16-Apr-13 5:15 
GeneralMy vote of 5 PinmemberGajendra Medatia5-Apr-13 0:12 
GeneralRe: My vote of 5 PinmemberChinmaya_Champatiray5-Apr-13 0:28 
GeneralMy vote of 4 PinmemberSRIRAM 24-Apr-13 20:59 
GeneralRe: My vote of 4 PinprofessionalChinmaya_Champatiray22-Apr-13 22:42 
GeneralMy vote of 4 PinmemberPaulo Zemek19-Mar-13 8:07 
GeneralRe: My vote of 4 PinmemberChinmaya_Champatiray19-Mar-13 8:25 
GeneralRe: My vote of 4 PinmemberPaulo Zemek20-Mar-13 6:32 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140709.1 | Last Updated 6 Jun 2014
Article Copyright 2013 by Chinmaya_Champatiray
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid