天天看點

設計模式六大原則(三)----依賴倒置原則

一. 什麼是依賴倒置原則

1.1 概念

依賴倒置原則(Dependence Inversion Principle, DIP), 其含義:

  1. 高層子產品不應該依賴低層子產品,兩者都應該依賴其抽象
  2. 抽象不應該依賴細節, 細節應該依賴于抽象
  3. 要針對接口程式設計,不要針對實作程式設計

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("奔馳跑起來了!");
    }
}

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);
    }
}
           

有一個駕駛員張三可以駕駛奔馳汽車, 于是最開始我們思考, 會有一個駕駛員類, 有一個奔馳汽車類. 随着業務的發展, 我們發現, 駕駛員張三還可以駕駛寶馬.

于是,我們定義一個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);
    }
}
           

似乎這樣就可以了, 但是這樣有什麼問題呢?

  1. 如果張三有一天要開大衆, 還要增加一個大衆車類, 同時還得挂載司機名下.
  2. 不是所有的人都要開奔馳, 開寶馬. 開大衆.

這就是面向實作程式設計的問題, 接下來我們就要考慮面向接口程式設計.

2.2 改進後的方案

public interface ICar {
    public void run();
}

public class Benz implements ICar{
    public void run() {
        System.out.println("奔馳跑起來了!");
    }
}

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 構造注入,在構造的時候注入依賴
           
  1. Setter方法注入
  2. 接口方法中注入(汽車的例子使用的就是此方法)

3.2 依賴倒置原則在設計模式中的展現

  1. 簡單工廠設計模式, 使用的是接口方法中注入
  2. 政策設計模式: 在構造函數中注入.

    具體的用法, 可以檢視以下兩篇文章:

    a. 簡單工廠設計模式:

    b. 政策設計模式:

設計模式六大原則(三)----依賴倒置原則

繼續閱讀