## 一、定义
依赖倒置原则(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点:
* 低层模块尽量都要有抽象类或接口,或者两者都有。
* 变量的声明类型尽量是抽象类或接口。
* 使用继承时遵循里氏替换原则。
- 前言
- 第一章 设计七大原则
- 第1节 开闭原则
- 第2节 依赖倒置原则
- 第3节 单一职责原则
- 第4节 接口隔离原则
- 第5节 迪米特法则
- 第6节 里氏替换原则
- 第7节 合成复用原则
- 第二章 简单工厂模式
- 第1节 使用场景
- 第2节 示例代码
- 第三章 创建者模式
- 第1节 工厂方法模式
- 第2节 抽象工厂模式
- 第3节 建造者模式
- 第4节 原型模式
- 第5节 单例模式
- 第四章 结构型模式
- 第1节 适配器模式
- 第2节 桥接模式
- 第3节 组合模式
- 第4节 装饰者模式
- 第5节 外观模式
- 第6节 享元模式
- 第7节 代理模式
- 第五章 行为模式
- 第1节 责任链模式
- 第2节 命令模式
- 第3节 迭代器模式
- 第4节 中介者模式
- 第5节 备忘录模式
- 第6节 观察者模式
- 第7节 状态模式
- 第8节 策略模式
- 第9节 模板方法模式
- 第10节 访问者模式
- 第11节 解释器模式