What is „Dependency Inversion Principle” (DIP) ?
It is the fifth rule of the SOLID design rules (it stands for D in SOLID acronym).
Definition
High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details.
Robert C. Martin (Uncle Bob)
In simpler words, dependencies should depend on abstraction as much as possible and not on a specific type.
Real-life example
Let’s say we have an vet application that check health of animals.
public class Launcher { public static void main(String[] args) { Vet vet = new Vet(); vet.checkHealth(AnimalType.dog); vet.checkHealth(AnimalType.cat); } }
public enum AnimalType { dog, cat }
public class Dog { public void checkHealth() { System.out.println("Checking dog health"); } }
public class Cat { public void checkHealth() { System.out.println("Checking cat health"); } }
public class Vet { private final Dog dog; private final Cat cat; public Vet() { this.dog = new Dog(); this.cat = new Cat(); } public void checkHealth(AnimalType animalType) { switch (animalType) { case dog: this.dog.checkHealth(); break; case cat: this.cat.checkHealth(); break; default: break; } } }
UML diagram of our application:
The Vet class is closely related to the Dog and Cat classes, it cannot exist without these two classes, due to that out program does not meet the DIP rule.
We can fix it by removing composition in Vet class.
public class Launcher { public static void main(String[] args) { Vet vet = new Vet(); vet.checkHealth(new Dog()); vet.checkHealth(new Cat()); } }
public interface Animal { void checkHealth(); }
public class Dog implements Animal { public void checkHealth() { System.out.println("Checking dog health"); } }
public class Cat implements Animal { public void checkHealth() { System.out.println("Checking cat health"); } }
public class Vet { public void checkHealth(Animal animal) { animal.checkHealth(); } }
Now, Vet class can exists without any other class. Moreover checkHealth method depends from abstraction, which is in line with the DIP rule.
UML diagram of our application after refactoring:
Why should I follow „Dependency Inversion Principle” ?
This rule helps to reduce the number of dependencies among modules and thanks to that code is easier to extend and maintain. Moreover classes are not tightly coupled with the lower-level objects and we can easily reuse the logic from the high-level modules.
What to look for?
DIP is the rule, which is really common while creating libraries/packages. It is strongly recommended, that such a code does not require an outside composition.