依赖倒置包含三层含义:
- 高层模块不应该依赖低层模块,二者都应该依赖其抽象
- 抽象不应该依赖细节
- 细节应该依赖抽象
这就要求模块之间的依赖不直接通过实现类发生,而是通过其接口或者抽象类发生,简单来说就是面向接口编程
依赖倒置可以减少类与类之间的耦合性,提高系统的稳定性
案例如下:
不使用依赖倒置的情况:
首先如果学生Student要学习Java课程,我们新建tom类和JavaCourse类,tom对象的study方法调用javaCourse对象的startCourse方法如下
Student:
public class Student {
public void study(JavaCourse course) {
course.startCourse();
}
}
JavaCourse:
public class JavaCourse {
public void startCourse(){
System.out.println("学习JAVA");
}
}
测试类:
public class DITest {
public static void main(String[] args) {
JavaCourse javaCourse = new JavaCourse();
Student tom = new Student();
tom.study(javaCourse);
}
}
可以得到结果如下:
这个代码里学生对象调用课程对象的开始课程方法实现学习课程的功能,初看好像没有问题,但是这两个之间的耦合非常大,如果此时有一门新的Python课程如下:
public class PythonCourse {
public void startCourse(){
System.out.println("学习Python");
}
}
我们的学生如果想学习Python就需要在Student增加学习Python的方法
所以这种结构就会使没新增一个课程我们的学生类就要进行相应的修改,底层模块对上层影响太大
我们做相应的修改:
使用依赖倒置的情况
1.首先我们新增一个ICourse的接口
public interface ICourse {
public void startCourse();
}
2.然后,每个课程都实现接口ICourse 及其相应的方法
JavaCourse :
public class JavaCourse implements ICourse{
public void startCourse(){
System.out.println("学习JAVA");
}
}
PythonCourse:
public class PythonCourse implements ICourse {
public void startCourse(){
System.out.println("学习Python");
}
}
学生类如下:
public class Student {
private ICourse course;
public Student(ICourse course) {
this.course = course;
}
public void study(ICourse course) {
course.startCourse();
}
}
测试类如下:
public static void main(String[] args) {
JavaCourse javaCourse = new JavaCourse();
Student student = new Student(javaCourse);
student.study(javaCourse);
}
这样,当我们要学习新的课程的时候,不用更改Student类,因为其使用的是课程的接口类,只要接口类不更改,该上层类就不需要更改,只用在实现的时候告诉Student的对象是具体使用接口类的哪个子类。方法可以如上面使用构造方法注入,也可以使用setCourse方法进行注入
相关类图如下: