Dependency Injection VS Dependency Inversion

Dependency Injection VS Dependency Inversion

"Dependency Injection" and "Dependency Inversion" both are very important terms in Software Engineering. Both deal with writing flexible and maintainable code.

Dependency Injection is a Software design pattern whereas Dependency Inversion is one of the SOLID principles.
Without dependency injection, it is not possible to achieve dependency inversion.

Let me explain these two terms with examples and how they help in writing good and easy-to-maintain software.

Note- Before proceeding, you must be good at OOPS concepts to understand this topic.

Dependency Injection

It is the process in which we inject (provide) the object of one class to another class that depends on the object of the injected class. Let us see the example.

In the above images, there is one class "Location" and another class "RealGPS".
The class "Location" prints the total of 'x' and 'y' points which are provided by the "RealGPS" class. The instance of the "RealGPS" class is passed as a parameter to the "Location" class constructor from the main method. Therefore class "RealGPS" instance is injected into class "Location" and hence "Location" depends on "RealGPS".

There is a main function which executes the code.

This code seems good so far but what if in future another GPS class is introduced?
For example, let's say another class with the name "MockGPS" is introduced which is used only for testing. Then in that case we need to instantiate the "MockGPS" class in the main method and pass it to the "Location" class constructor. But we cannot keep on changing the main method based on the different scenarios.
Here comes the principle of Dependency Inversion. Let us understand it through the same example.

Dependency Inversion

It states that high-level modules should not depend upon low-level modules. Both should depend upon abstractions. Secondly, abstractions should not depend upon details. Details should depend upon abstractions.
High-level modules are the classes that depend on other classes and low-level modules are the classes that are independent of any other classes. Here "Location" class is the higher-level module.
To achieve dependency inversion we will create an interface with the name "GPS" and inherit it inside "RealGPS" and "MockGPS" classes.
The methods "getPointX()" & "getPointY()" are overridden inside "RealGPS" and "MockGPS" classes.
Now in the main method, we can pass the "RealGPS" and "MockGPS" objects in the "Location" class constructor by instantiating them through "GPS" interface pointer. (Run time polymorphism).
Now based on the build type whether production build or testing build we can decide which "GPS" class to use.

The class "Location" no more depends on the class "RealGPS" or "MockGPS" rather depends on the abstraction that is the "GPS" interface. Hence, dependency inversion is achieved.

For type mockGps object, the output would be 23.

For type realGps object, the output would be 8.

In the above example, I have created a helper class "GPSObject" which will provide me with the objects of different "GPS" classes. The below image shows the helper class implementation.


As the project size grows, software design patterns and principles help a lot in writing clean code. Both concepts explained above, help in writing flexible, maintainable and extensible code.