六大設計原則(三)DIP依賴倒置原則

来源:https://www.cnblogs.com/quinntian/archive/2019/04/19/10739188.html
-Advertisement-
Play Games

依賴倒置原則DIP(Dependence Inversion Principle) 依賴倒置原則的含義 高層模塊不能依賴低層模塊,二者都應該依賴其抽象。 抽象不應該依賴於細節。 細節應該依賴抽象。 什麼是 高層模塊?低層模塊 ? 每一個原子邏輯就是低層模塊,原子邏輯再組就是高層模塊。 什麼是 抽象和 ...


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

依賴倒置原則的含義

  • 高層模塊不能依賴低層模塊,二者都應該依賴其抽象。
  • 抽象不應該依賴於細節。
  • 細節應該依賴抽象。

什麼是高層模塊?低層模塊
每一個原子邏輯就是低層模塊,原子邏輯再組就是高層模塊。
什麼是抽象和細節
抽象是抽象類,不可被實例化。
細節是實現類,比如實現的介面或繼承抽象類的子類,可以被實例化。

表現在Java語言中就是面向介面編程

  • 模塊間的依賴是通過抽象來實現的,具體的實現類之間不能發生直接的依賴。
  • 介面或抽象類不能依賴與實現類。
  • 實現類依賴介面或抽象類。
    ***
    我們假設有三個類,一個為場景類,一個為司機類,一個為賓士類。通過這三個類我們便可以實現司機開動汽車這個場景。如圖
    司機駕駛賓士車類圖
    具體的實現代碼如下
    司機類
package des.DIP;
//司機類
public class Driver {
    //司機駕駛車 緊耦合
    public void drive(Benze benze){
        benze.run();
    }
    //司機駕駛寶馬車 緊耦合
    public void drive(BMW bmw){
        bmw.run();
    }
}

賓士類

package des.DIP;
//賓士車
public class Benze {
    public void run(){
        System.out.print("賓士車開始運行...");
    }
}

場景類

package des.DIP;
//場景類
public class Client {
    public static void main(String[] args){
        //創建一個司機
        Driver zs = new Driver();
        //創建一個賓士車
        Benze benze = new Benze();
        //司機可以開賓士車
        zs.drive(benze);
        //假設此時增加一個寶馬車呢?還要再增加一個方法,並且重新創建
        //一個還好若是很多呢?難道要在司機類聲明很多方法嗎?
        BMW bmw = new BMW();

    }

}
package des.DIP;
//寶馬車
public class BMW {
    //寶馬車當然也可以開動
    public  void run(){
        System.out.print("寶馬車開動...");
    }
}

程式正常的寫法就是如此,但是如果我們考慮下麵一個問題,司機並不是只會開著一輛Benze牌的車,假如我們再假如一個BMW(寶馬)牌的車,我們傳統的做法就是再新建一個類,然後再司機類中再添加一個drive BMW的方法。假如我們要添加無數品牌的汽車呢,難道還要再司機類中添加無數的drive方法嗎?他們都有著相同的方法名,只是傳入的汽車型號不同。
顯然,傳統的drive方法的寫法,具有緊耦合性,只要車型變更,就不能再使用了。其導致的結果就是系統的可維護性大大降低,可讀性也大大降低
*
解決方法
使用依賴倒置原則**

DIP第一種方法 介面註入法

建立兩個介面,IDriver和ICar
file
此時業務的場景類就可以改寫成如下

package des.DIP;

public class Client1 {
    public static void main(String[] args){
        //創建一個司機
        /**
         * 此處明確兩個概念:
         * IDriver 叫做錶面類型, Driver1 叫做實際類型  或稱抽象類型和實際類型
         *
         * 此後所有的操作均是對抽象介面的操作,具體屏蔽了細節
         */
        IDriver ds = new Driver1();
        ICar c = new Bmw1();
        ds.drive(c);


    }
}

錶面類型和實際類型: IDriver 叫做錶面類型, Driver1 叫做實際類型 或稱抽象類型和實際類型

下麵是介面類和實現類參考代碼:

package des.DIP;
//司機介面
public interface IDriver {
    //司機可以駕駛汽車,什麼汽車不用管即抽象類(松耦合)
    public void drive(ICar car);
}
package des.DIP;
//抽象汽車類
public interface ICar {
    //汽車啟動
    public void run();
}
package des.DIP;

public class Driver1 implements  IDriver {
    @Override
    public void drive(ICar car) {
        car.run();
    }
}
package des.DIP;

public class Bmw1 implements  ICar {
    @Override
    public void run() {
        System.out.print("寶馬車開始運行...");
    }
}
package des.DIP;

public class Benze1 implements  ICar {
    @Override
    public void run() {
        System.out.print("賓士車開始運行...");
    }
}

假設我們項目中有兩個類是依賴關係,此時我們只需要定義兩個抽象類就可以獨立開發了。

DIP第二種方法 構造函數傳遞依賴對象

package des.DIP;
//司機介面
public interface IDriver {
    //司機可以駕駛汽車,什麼汽車不用管即抽象類(松耦合)
    public void drive(ICar car);
    /***************************/
    public void drive();
}
package des.DIP;

public class Driver1 implements  IDriver {
    /******************************************************/
    private ICar car;
    //構造函數註入
    public Driver1(ICar _car){
        this.car = _car;
    }
    @Override
    public void drive() {
        this.car.run();
    }
    /******************************************************/
    @Override
    public void drive(ICar car) {
        car.run();
    }

    
}
IDriver ds1 = new Driver1(new Bmw1());
ds.run();

運行結果
file
構造函數依賴註入理解圖示
file
file
file

DIP第三種方法 setter方法傳遞依賴對象

file
file
file
代碼參考

package des.DIP;
//司機介面
public interface IDriver {
    public void setCar(ICar car);
    public void drive();

}
package des.DIP;
public class Driver1 implements  IDriver {
    /******************************************************/
    private ICar car;
        @Override
    public void setCar(ICar car) {
        this.car.run();
    }
  
    @Override
    public void drive() {
        this.car.run();
    }

}
package des.DIP;

public class Client1 {
    public static void main(String[] args){
     
       IDriver ds1 = new Driver1();
        ds1.setCar(new Bmw1());
        ds1.drive();


    }
}

DIP總結

  • DIP本質就是通過抽象類來實現彼此獨立,互不影響
  • 依賴倒置的核心是面向介面編程,即上面的第一種方法。
  • 依賴倒置的具體使用規則如下
    • 每個類儘量有介面或抽象類,或者二者都有。
    • 變數的錶面類型儘量是介面或抽象類。
    • 任何類不應該從具體類派生。
    • 儘量不要覆寫基類的方法。
    • 結合里氏替換原則進行。
  • 依賴倒置需要審時度勢,而不是永遠抓住這個原則不放,任何一個原則的優點都是有限的。

對於倒置的理解

從反面講:什麼是正置?如上例子,我們開什麼型號的車,就依賴什麼樣型號的車。不存在什麼抽象類與介面,直接單獨建立即可,需要什麼建立什麼。但是依賴倒置?就是對車進行抽象,抽象出類和介面,建立抽象間的依賴。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、路由機制(靜態資源文件處理) 1.1 Nodejs沒有根目錄 MIME類型:http://www.w3school.com.cn/media/media_mimeref.asp 在Apache中,它會自動將htdocs文件夾提供靜態化路由服務。 但是Nodejs沒有這個機制。 在文件夾中創建這樣 ...
  • 在單頁面應用程式(SPA)中,有些頁面的佈局結構是上下兩塊是固定,中間內容是變化的。這時在入口處固定上下部分就可以很好的解決這一問題。有少部分頁面沒有上下部分或不需要(如:用戶註冊、登陸頁面),針對這一情況怎麼解決 相容這兩種情況解決方案: App.vue 在入口處單個路由輸出 Frame.vue ...
  • 好處:方便了後端對HTTP請求中參數進行核驗,只需一次編寫效驗器,一行代碼便可對所有參數的pojo進行參數核驗!而且更改效驗邏輯時只需要更改效驗器類即可,實現瞭解耦合。 只需要程式員按照規範開發一個ParameterValidator類(如下圖1),將所有效驗方法寫在該類中即可在任意地方使用一行代碼 ...
  • 原型模式概述 定義:使用原型實例指定待創建對象的類型,並且通過複製這個原型來創建新的對象。簡單的來說就是克隆(Clone),通過已經存在的,將其複製而產生新的。原型模式屬於創建型模式,將一個原型對象傳給要發動創建的對象(客戶端對象),該對象通過請求原型對象複製自己來實現創建過程。 既然是通過Clon ...
  • Spring Boot 2.0 升級指南 前言 Spring Boot已經發佈2.0有5個月多,多了很多新特性,一些坑也慢慢被填上,最近有空,就把項目中Spring Boot 版本做了升級,順便整理下升級的時候遇到的一些坑,做個記錄。後續的教程就以最新的2.03版本為主。參考官方文檔翻譯 在你開始之 ...
  • 本文將從簡單的場景引入, 逐步優化, 最後給出具體的責任鏈設計模式實現. 場景引入 首先我們考慮這樣一個場景: 論壇上用戶要發帖子, 但是用戶的想法是豐富多變的, 他們可能正常地發帖, 可能會在網頁中淺入html代碼, 可能會使用錯誤的表情格式, 也可能發送一些敏感信息. 作為論壇的管理員必須對用戶 ...
  • SSO 單點登錄:一次登錄,處處登錄。 只需在一個登錄認證服務下進行登錄後,就可訪問所有相互信任的應用 同域 SSO 1. session-cookie機制:服務端通過cookie認證客戶端。 用戶第一次登錄後,服務端將返回一個cookie給客戶端(這個cookie包含session id),用戶下 ...
  • 之前已經帶大家稍微入門了工廠模式(即簡單工廠模式)的方法,沒看過的朋友可以移步去查看一番。 "設計模式之工廠模式(一)" 。今天我們繼續吃著披薩,學習著工廠模式的接下來部分吧。 加盟披薩店 我們先前的披薩店已經經營有成,擊敗了部分競爭者,接下來的計劃就是開加盟店。作為經營者,你肯定希望確保加盟店運營 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...