Before going through this article, I strongly recommend reading my previous articles.
Dependency Inversion Principle
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, and 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.
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, that 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.
The solution to this is a USB port.
If I have a USB port then I can easily attach any device to my machine and perform my task.
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.
Figure 3. Class diagram of tight coupling
Public Class Customer
{
CustomerRepository CustomerRepository;
Public Customer
{
CustomerRepository = new CustomerRpository();
}
Public bool Save()
{
CustomerRepository.Save();
}
}
Public class CustomerRepository
{
Public bool Save(dattype data)
{
//Sql Connection object and Save data in Sql server
}
}
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.
Figure 4. Class diagram where the customer depends on abstraction
Public Class Customer
{
CustomerRepository CustomerRepository;
Public Customer
{
CustomerRepository = new CustomerRpository();
}
Public bool Save()
{
CustomerRepository.Save();
}
}
Public class CustomerRepository
{
Public bool Save(dattype data)
{
//Sql Connection object and Save data in Sql server
}
}
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 consumption 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 of the Dependency Inversion Principle
Application modules become tightly coupled, which means.
- The testability of the module becomes difficult.
- Parallel development of the module becomes difficult.
- Many changes are required when there is a modification in the module and when there are changes in the module it depends on.