definition:
High-level modules should not rely on low-level modules, both should rely on their abstraction; abstractions should not rely on details; details should rely on abstraction.
The origin of the problem: Class A directly depends on class B. If you want to change Class A to depend on class C, you must achieve it by modifying the code of class A. In this scenario, Class A is generally a high-level module that is responsible for complex business logic; Class B and Class C are low-level modules that are responsible for basic atomic operations; if Class A is modified, it will bring unnecessary risks to the program.
Solution: Modify class A to depend on interface I, and class B and class C each implement interface I. Class A indirectly contacts class B or class C through interface I, which will greatly reduce the chance of modifying class A.
The principle of dependence inversion is based on the fact that abstract things are much more stable than variability in details. The architecture built on abstract is much more stable than the architecture built on details. In Java, abstract refers to an interface or abstract class, and details are specific implementation classes. The purpose of using interface or abstract class is to formulate specifications and contracts without involving any specific operations, and to hand over the task of presenting details to their implementation classes for completion.
The core idea of the principle of dependency inversion is interface-oriented programming. We will still use an example to illustrate where interface-oriented programming is better than implementation-oriented programming. The scene is like this: the mother tells a story to her child. As long as she gives her a book, she can tell stories to her child according to the book.
example:
Inversion of illegal dependence
public class Student { public void read(Book book){ System.out.println("Student starts reading: "+book.getName()); } } public class Book { public String getName() { return "book"; } }
When students need to read web pages, they need to modify the Student class, which is very unfriendly design. Let’s look at the example of adhering to the principle of inversion of dependence.
public interface Person { public void read(Reader reader); } public interface Reader { public String getName(); } public class Student implements Person{ @Override public void read(Reader reader) { System.out.println("Student start reading: "+reader.getName()); } } public class Book implements Reader { public String getName() { return "book"; } } public class Website implements Reader { public String getName() { return "web page"; } } public class Test { public static void main(String[] args) { Person student = new Student(); student.read(new Book()); student.read(new Website()); } }
In the read method we use the interface as a parameter.
Summarize:
1. It is best to have interfaces or abstract classes for each class, or both interfaces and abstract classes.
2. The variable declaration is preferably an interface or an abstract class.
3. Abide by the principle of substitution during inheritance.