Thursday, September 17, 2015

Dependency Inversion Principle in .NET

In today's blog post, I will be discussing the "D" in SOLID principles i.e. Dependency Inversion Principle (DIP).

Dependency Inversion Principle (DIP)

According to Wikipedia, Dependency Inversion Principle states: 
i) High level modules should not depend on low level modules. Both should depend on abstractions.
ii) Abstractions should not depend on details. Details should depend on abstractions.


Dependency Inversion Principle



Following Dependency Inversion Principle DIP helps you create loose coupling, so that any change in the low level module will not affect the higher level modules. The higher level classes should have loose coupling with lower level classes.

Dependency Inversion Principle helps us to reduce the dependency from one concrete class to another concrete class. By introducing dependency on interfaces instead of classes we get loose coupling which makes our code more supple and easier to change in future.

Let's take a look at an example:

public class Employee

{

   /*

  ;   other properties and methods 

   */        

   public Employee Details(int id)

   {

       private FileLogger fileLogger = new FileLogger();

       fileLogger.Log("Reading Employee " + id);

       Employee employee = db.Employees.Find(id);

       if (employee == null)

       {

        fileLogger.Log("Employee not Found with id = " + id);

        return null;

       }

       fileLogger.Log("Returning Employee with id = " + id);

       return employee;

   }

   //....

}

Here, the Employee class has implicit dependency on FileLogger class. In future, if you have to change the logging mechanism to suppose EmailLogger, imagine the number of places you might have to change the code.

So in order to make them loosely coupled we can create an ILogger interface and make the Employee class use the interface instead of concrete class. 

 public interface ILogger

{

        void Log(string message);

}





public class FileLogger : ILogger

{

        public void Log(string message)

        {

            //implement file logging

        }

}





public class EmailLogger : ILogger

{

        public void Log(string message)

        {

            //implement email logger

        }

}


Please note that, just by using interfaces we can't say that we have applied Dependency Inversion Principle. The higher level objects should own and control the contracts and lower level modules should simply implement them. Higher level modules should not care about how the lower level implementation is done.


public class Employee

{

     private ILogger logger;

     public Employee(ILogger logger)

     {

         this.logger = logger;

     }



     /*

       other properties and methods 

     */



     public Employee Details(int id)

     {

         logger.Log("Reading Employee " + id);

         Employee employee = db.Employees.Find(id);

         if (employee == null)

         {

             logger.Log("Employee not Found with id = " + id);

             return null;

         }

         logger.Log("Returning Employee with id = " + id);

         return employee;

     }

     //....

} 

Please note the constructor of the Employee class with parameter of ILogger. In this way, Employee class explicitly defines that it has dependency on ILogger. Anybody who is consuming the Employee class needs to pass in the concrete implementation of ILogger to be used. So now it's not the responsibility of the Employee class to know what type of logging mechanism is being used.


Three Primary Techniques

Let's gloss over 3 basic techniques used to apply DIP

Constructor Injection

Dependencies are passed in through constructor. This is one of the most common way to implement this. All the dependencies are mentioned as constructor parameters. One of the cons with this is we might not be using all the dependencies all the time, so extra objects in memory and constructor can become too long.

Property Injection

Dependencies are set through property setters. This is more flexible as you can set the properties as needed. The problem is it can lead to classes in inconsistent state. If some calling code doesn't set the required property then we can get erroneous results.

Parameter Injection

Dependencies passed in through method parameter. This is most granular but it can again lead to long list of parameters which is another problem in itself. 



Ioc Container

We can't complete the discussion of Dependency of Inversion Principle without glossing over Ioc containers as well. These manage dependencies and implementations to be used. They automatically resolve dependencies at runtime or start up of the application. For example: Unity, Autofac, Ninject, etc. We will need a separate post on Ioc containers to talk about them at length.

Conclusion

So we saw how Dependency Inversion Principle can be helpful and help us write more loosely coupled code. If we see our classes depending on other concrete classes then we might want to apply some DIP there. So like other SOLID principles this is another principle to keep in mind while coding. This is more useful when we write components for other application to consume. You can apply it at places which you think might be requiring different implementations in future.

For future updates to my weekly blog, please subscribe to my blog via the "Subscribe To Weekly Post" feature at the right and follow me on Twitter. Until then Happy Coding :)



1 comment:

  1. Ugh, no. Inverting a dependency doesn't eliminate it.

    The title alone frightens me. Dependency inversion is a technique, not a principle. Apply it twice and you are back to where you started. (Undoing haphazardly applied inversions is a common task when working with legacy code.)

    ReplyDelete