設計模式六大原則(三)—-依賴倒置原則
一. 什麼是依賴倒置原則
1.1 概念
依賴倒置原則(Dependence Inversion Principle, DIP), 其含義:
- 高層模組不應該依賴低層模組,兩者都應該依賴其抽象
- 抽象不應該依賴細節, 細節應該依賴於抽象
- 要針對介面編程,不要針對實現編程
1.2 什麼是依賴呢?
這裡的依賴關係我們理解為UML關係中的依賴。簡單的說就是A use B,那麼A對B產生了依賴。具體請看下面的例子。
從上圖中我們可以發現, 類A中的方法a()裡面用到了類B, 其實這就是依賴關係, A依賴了B. 需要注意的是: 並不是說A中聲明了B就叫依賴, 如果引用了但是沒有真實調用方法, 那麼叫做零耦合關係. 如下圖:
1.3 依賴的關係種類
1. 零耦合關係:如果兩個類之間沒有耦合關係,稱之為零耦合
2. 直接耦合關係: 具體耦合發生在兩個具體類(可實例化的)之間,經由一個類對另一個類的直接引用造成。
3. 抽象耦合關係: 抽象耦合關係發生在一個具體類和一個抽象類(或者java介面)之間,使兩個必須發生關係的類之間存在最大的靈活性。
依賴倒轉原則就是要針對介面編程,不要針對實現編程。這就是說,應當使用介面或者抽象類進行變數的類型聲明,參數的類型聲明,方法的返回類型說明,以及數據類型的轉換等。
二. 依賴倒置的案例
2.1 初步設計方案
public class Benz {
public void run() {
System.out.println("Benz跑起來了!");
}
}
public class Driver {
private String name;
public Driver(String name) {
this.name = name;
}
public void driver(Benz benz) {
benz.run();
}
}
public class CarTest {
public static void main(String[] args) {
Benz benz = new Benz();
Driver driver = new Driver("張三");
driver.driver(benz);
}
}
有一個駕駛員張三可以駕駛Benz汽車, 於是最開始我們思考, 會有一個駕駛員類, 有一個Benz汽車類. 隨著業務的發展, 我們發現, 駕駛員張三還可以駕駛寶馬.
於是,我們定義一個BM類,
public class BM {
public void run() {
System.out.println("寶馬跑起來了!");
}
}
這時, 張三如果想要開寶馬, 就要將寶馬註冊在他名下.
public class Driver {
private String name;
public Driver(String name) {
this.name = name;
}
public void driver(Benz benz) {
benz.run();
}
public void driver(BM bm) {
bm.run();
}
}
public class CarTest {
public static void main(String[] args) {
Benz benz = new Benz();
BM bm = new BM();
Driver driver = new Driver("張三");
driver.driver(benz);
driver.driver(bm);
}
}
似乎這樣就可以了, 但是這樣有什麼問題呢?
- 如果張三有一天要開大眾, 還要增加一個大眾車類, 同時還得掛載司機名下.
- 不是所有的人都要開Benz, 開寶馬. 開大眾.
這就是面向實現編程的問題, 接下來我們就要考慮面向介面編程.
2.2 改進後的方案
public interface ICar {
public void run();
}
public class Benz implements ICar{
public void run() {
System.out.println("Benz跑起來了!");
}
}
public class BM implements ICar{
public void run() {
System.out.println("寶馬跑起來了!");
}
}
public interface IDriver {
public void driver(ICar car);
}
public class Driver implements IDriver{
@Override
public void driver(ICar car) {
car.run();
}
}
public class CarTest {
public static void main(String[] args) {
IDriver driver = new Driver();
driver.driver(new Benz());
driver.driver(new BM());
}
}
修改後的程式碼, 提煉出來一個IDriver介面和ICar介面, 面向介面編程. IDriver的實現類駕駛員可以driver任何類型的汽車, 所以傳入參數也是一個介面ICar. 任何類型的汽車, 都可以通過實現ICar介面註冊為一種新的汽車類型. 當客戶端調用的時候, 將對應的汽車傳入就可以了.
三. 依賴的方式
3.1 依賴注入主要有三種方式:
1 構造注入,在構造的時候注入依賴
- Setter方法注入
- 介面方法中注入(汽車的例子使用的就是此方法)
3.2 依賴倒置原則在設計模式中的體現
- 簡單工廠設計模式, 使用的是介面方法中注入
- 策略設計模式: 在構造函數中注入.
具體的用法, 可以查看以下兩篇文章:
a. 簡單工廠設計模式:
b. 策略設計模式: