Dependency Inversion Principle

Before going through this article, I strongly recommend reading my previous articles:

The Dependency Inversion Principle is one of the SOLID principles defined by Robert C. Martin. This principle is about dependencies among the components (such as two modules, two classes) of the software.

The principle says that high-level modules should depend on abstraction, not on the details, of low level modules, in other words not the implementation of the low level module. Abstraction should not depend on details. Details should depend on abstraction. In simple words the principle says that there should not be a tight coupling among components (in other words two modules, two classes) of software and to avoid that, the components should depend on abstraction, in other words a contract (interface or abstract class).

Dependency Inversion Principle in Real life

To understand the second problem better way, let's see a real life scenario of a computer or laptop.

Different Port
Figure 1: Various Port

As you can see in the preceding image we have a port for each external device to which I can associate an external device and do our work.

But the problem with this is, I cannot attach my keyboard to a printer port and vice versa. The same problem occurs with the other devices. So this is like a tight coupling, that I cannot change my external device on the given interface, in other words on which I depend.

Solution to this is USB port.

If I have a USB port then I can easily attach any device to my machine and perform my task.

USB port
Figure 2: USB port

Example of Dependency Inversion Principle in Application Development

The following is a class diagram of tight coupling that does not follow the principle.

class diagram of tight coupling
Figure 3: Class diagram of tight coupling
  1. Public Class Customer  
  2. {  
  3.     CustomerRepository CustomerRepository;  
  4.     Public Customer  
  5.     {  
  6.         CustomerRepository = new CustomerRpository();  
  7. }  
  8.   
  9. Public bool Save()  
  10. {  
  11.     CustomerRepository.Save();  
  12. }  
  13. }  
  14.   
  15. Public class CustomerRepository  
  16. {  
  17.     Public bool Save(dattype data)  
  18. {  
  19.               //Sql Connection object and Save data in Sql server   
  20. }  
  21. }  
The preceding code is tightly coupled because the current repository deals with the SQL server. So if the requirement is to use an Oracle server then there is modification required for the Customer class.

So to avoid that, make the customer class depend on abstraction. The following is an image of a class diagram where the customer depends on abstraction and supports both SQL and Oracle servers.

Class diagram
Figure 4: Class diagram where the customer depends on abstraction.
  1. Public Class Customer   
  2. {  
  3.     CustomerRepository CustomerRepository;  
  4.     Public Customer   
  5.     {  
  6.         CustomerRepository = new CustomerRpository();  
  7.     }  
  8.   
  9.     Public bool Save()   
  10.     {  
  11.         CustomerRepository.Save();  
  12.     }  
  13. }  
  14.   
  15. Public class CustomerRepository   
  16. {  
  17.     Public bool Save(dattype data)   
  18.     {  
  19.         //Sql Connection object and Save data in Sql server     
  20.     }  
  21. }  
So in the preceding code the customer class depends on ICustomerRepository abstraction, in other words an interface. Another thing is here the customer class receives a dependency via consumtion of the customer class or using a dependency container.

Note: Here is an example of the class but the same goes for the modules designed in software because dependency inversion is about providing a set of abstraction policies on which the details depend and the policy that provides flexibility in the software system.

Disadvantages

Application modules become tightly coupled, that means: 
  1. The testability of the module becomes difficult.

  2. Parallel development of the module becomes difficult.

  3. Many changes are required when there is modification in the module and when there are changes in the module it depends on.

Read more Dependency Injection talks about the disadvantages and advantages of using dependency inversion.

Note: Dependency Injection is not the same as Dependency Inversion because Dependency Inversion is about defining an abstraction policy for the software module whereas Dependency Injection is a set of patterns to supply dependency.