🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 一、定义 依赖倒置原则(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. 并能够降低修改程序所造成的风险。 ## 四、示例 ~~~ /** * 高层模块 */ public class ZhangSan { //张三开始学习 public void study(JavaCourse javaCourse){ javaCourse.startStudy(); } } ~~~ ~~~ /** * 底层模块 */ public class JavaCourse { public void startStudy(){ System.out.println("开始学习JAVA"); } } ~~~ ~~~ 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抽象化,抽取的共同点。 ~~~ public interface Course { void startStudy(); } ~~~ ~~~ public class ZhangSan { public void study(Course course){ course.startStudy(); } } ~~~ ~~~ 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注入: ~~~ public class ZhangSan { private Course course; public void setCourse(Course course) { this.course = course; } public void study(){ this.course.startStudy(); } } ~~~   构造器注入: ~~~ public class ZhangSan { private Course course; public ZhangSan(Course course) { this.course = course; } public void study(){ this.course.startStudy(); } } ~~~ 继承关系: ![](https://img.kancloud.cn/a1/90/a1907abd62d48462e39530cf6be87348_859x414.png) 在实际编程中,我们一般需要做到如下3点: * 低层模块尽量都要有抽象类或接口,或者两者都有。 * 变量的声明类型尽量是抽象类或接口。 * 使用继承时遵循里氏替换原则。