## 一、定義
依賴倒置原則(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();
}
}
~~~
繼承關系:

在實際編程中,我們一般需要做到如下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節 解釋器模式