一、定义
依赖倒置原则(Dependence Inversion Principle,DIP)是指设计代码结构时,高层模块不应该依赖底层模块,二者都应该依赖其抽象。抽象不应该依赖细节;细节应该依赖抽象。
核心思想:面向接口编程
二、描述
类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。
可以将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。
三、优点
1.可以减少类与类之间的耦合性,提高系统的稳定性。
2.提高代码的可读性和可维护性。
3.并能够降低修改程序所造成的风险。
四、示例
我们以一个学习案例为演示。
/**
* Create By Ke Shuiqiang 2020/3/5 15:59
* 高层模块
*/
public class ZhangSan {
//张三开始学习
public void study(JavaCourse javaCourse){
javaCourse.startStudy();
}
}
/**
* Create By Ke Shuiqiang 2020/3/5 16:43
* 底层模块
*/
public class JavaCourse {
public void startStudy(){
System.out.println("开始学习JAVA");
}
}
/**
* Create By Ke Shuiqiang 2020/3/5 16:40
*/
public class Test {
public static void main(String[] args) {
ZhangSan zhangSan = new ZhangSan();
System.out.println("准备学习");
zhangSan.study(new JavaCourse());
System.out.println("学习完毕");
}
}
准备学习
开始学习JAVA
学习完毕
在这个示例中告诉我们,张三很喜欢学习,并且喜欢学习JAVA,但是有一天张三忽然不想学JAVA了,他想学点别的比如Python。
/**
* Create By Ke Shuiqiang 2020/3/5 16:43
*/
public class PythonCourse {
public void startStudy(){
System.out.println("开始学习Python");
}
}
但是我们发现,张三没有这个能力,他只会学习JAVA。如果我们想赋予张三这个能力,我们只能修改ZhangSan中的代码,但是张三每次想学习新得知识,我们都要修改ZhangSan中的代码吗?这显然是及其不合理的设计,原因就是ZhangSan和JavaCourse之间的耦合度太高了,必须降低它们之间的耦合度。
我们可以把JavaCourse和PythonCourse抽象化,抽取的共同点。
/**
* Create By Ke Shuiqiang 2020/3/5 17:12
*/
public interface Course {
void startStudy();
}
/**
* Create By Ke Shuiqiang 2020/3/5 15:59
*/
public class ZhangSan {
public void study(Course course){
course.startStudy();
}
}
/**
* Create By Ke Shuiqiang 2020/3/5 16:40
*/
public class Test {
public static void main(String\[\] args) {
ZhangSan zhangSan = new ZhangSan();
System.out.println("准备学习");
zhangSan.study(new JavaCourse());
System.out.println("学习完毕");
System.out.println("------------------");
System.out.println("准备学习");
zhangSan.study(new PythonCourse());
System.out.println("学习完毕");
}
}
准备学习
开始学习JAVA
学习完毕
------------------
准备学习
开始学习Python
学习完毕
修改后的代码ZhangSan不与任何具体的实现产生依赖关系,而是与它们的接口Course产生依赖关系。这样就符合了我们的依赖倒置原则。不管以后ZhangSan想学习AI还是PHP都不需要修改ZhangSan中的代码,只要实现Course就可以。
实际上这是一种大家非常熟悉的方式,叫依赖注入。注入的方式还有构造器方式和setter方式。
setter注入:
/**
* Create By Ke Shuiqiang 2020/3/5 15:59
*/
public class ZhangSan {
private Course course;
public void setCourse(Course course) {
this.course = course;
}
public void study(){
this.course.startStudy();
}
}
构造器注入:
/**
* Create By Ke Shuiqiang 2020/3/5 15:59
*/
public class ZhangSan {
private Course course;
public ZhangSan(Course course) {
this.course = course;
}
public void study(){
this.course.startStudy();
}
}
在实际编程中,我们一般需要做到如下3点:
- 低层模块尽量都要有抽象类或接口,或者两者都有。
- 变量的声明类型尽量是抽象类或接口。
- 使用继承时遵循里氏替换原则。
参考: https://blog.csdn.net/zhengzh...