1. 程式人生 > >第2章 面向物件的設計原則(SOLID):3_依賴倒置原則(DIP)

第2章 面向物件的設計原則(SOLID):3_依賴倒置原則(DIP)

3. 依賴倒置原則(Dependence Inversion Principle,DIP)

3.1 定義

(1)要依賴抽象不要依賴具體的實現類。簡單的說就是對抽象(或介面)進行程式設計,不要依賴實現進行程式設計,這樣就降低了客戶與實現模組間的耦合。包含3層含義:

  ①高層模組不應依賴低層模組,兩者都應該依賴於抽象

  ②抽象不應該依賴細節

  ③細節應該依賴於抽象

(2)何為“高層模組”和“低層模組”

  ①“低層模組”:每個邏輯的實現都是原子邏輯組成,不可分割的原子邏輯就是低層模組。一般和具體實現相關。

  ②“高層模組”:原子邏輯再組裝就是高層模組,一般和業務邏輯相關。如客戶端。

(3)何為“倒置”

  ①“依賴正置”:就是類間的依賴是實實在在的實現類間的依賴,也就是面向實現程式設計,這符合人的正常思維。如我們開賓士車就是依賴賓士車,使用膝上型電腦就直接依賴膝上型電腦。

  ②“依賴倒置”:程式設計是對現實世界事物進行抽象,然後我們根據系統設計的需要產生了對抽象的依賴,代替了人的傳統思維中事物間的依賴,這叫“倒置”。

3.2  依賴實現程式設計存在的問題及改進

(1)Driver只能開賓士車!

【程式設計實驗】司機只能看賓士車

//面向物件設計原則:DIP依賴倒置原則
//司機只能開賓士車——依賴具體實現

#include <stdio.h>

//賓士車類
class Benz
{
public:
    void run()
    {
        printf("Benz Runing...\n");
    }
};

//司機類
class Driver
{
public:
    //司機類不是依賴於抽象,而是依賴具體的汽車Benz,
    //導致司機只能開賓士,不能開其它車的尷尬!
    void drive(Benz& benz)
    {
        benz.run();
    }
 
};

int main()
{
    Driver zhangSan;
    Benz benz;
    
    //張三開賓士車
    zhangSan.drive(benz); //引數為Benz型別,張三隻會開賓士!
    
    return 0;
}

(2)解決方案——引入依賴倒置!

  ①通過IDriver和ICar兩個介面來類間的耦合,引入依賴倒置原則

  ②汽車提供run方法。司機的職能就是駕駛汽車,必須實現Drive方法。當新增加汽車類時只要該汽車實現了ICar介面,司機就可以開了。

  ③Client是高層業務邏輯,它對低層的依賴是建立在抽象上。

【程式設計實驗】司機可開各類車

//面向物件設計原則:DIP依賴倒置原則
//司機可開任何汽車——依賴抽象/介面

#include <stdio.h>

//汽車介面
class ICar
{
public:
    virtual void run() = 0;
};

//賓士車類
class Benz : public ICar
{
public:
    void run(){printf("Benz runing...\n");}
};

//寶馬車類
class BWM : public ICar
{
public:
    void run(){printf("BWM runing...\n");}
};

//司機介面
class IDriver
{
public:
    //是司機應該會駕駛汽車
    virtual void drive(ICar& car) = 0; //依賴介面
};

//司機類
class Driver : public IDriver
{
public:
    void drive(ICar& car) //實現介面
    {
        car.run();
    }
};

int main()
{
    Driver zhangSan;
    Benz benz;
    BWM  bwm;
    
    //張三開賓士車
    zhangSan.drive(benz); 
    
    //張三開寶馬
    zhangSan.drive(bwm);
    
    return 0;
}

3.3 依賴的3種寫法(詳見第1章)

(1)建構函式傳遞依賴物件

(2)Setter方法傳遞賴物件

(3)通過介面宣告依賴物件(如程式設計實驗2)

3.4 最佳實踐

(1)每個類儘量都有介面或抽象類,或兩者都有,這是依賴倒置的基本要求,有了抽象才可能依賴倒置

(2)宣告變數時儘量用介面或抽象類,例項化再用具體的類

(3)任何類都不應該從具體的類派生(或者繼承自具體類時不應超過兩層)

(4)儘量不要覆蓋基類己經實現的的方法。

(5)結合里氏替換原則,對子類進行設計。以便實現類能準確的實現業務邏輯又不違反LSP原則。