設計模式七大原則—依賴倒置原則

来源:https://www.cnblogs.com/green-jcx/archive/2022/05/05/DI.html
-Advertisement-
Play Games

1.基本介紹 1.1.概念 高層模塊不能依賴於一個“具體化、細節化”的低層模塊,而是通過一個抽象的“規範/標準”建立兩者之間的依賴關係,簡言之就是:不依賴於實現,而是依賴於抽象。這裡“實現”一詞有的地方也稱為“細節”,在編碼中主要體現的是我們根據業務模型具體自定義的普通類,比如:員工類、商品類等。而 ...


1.基本介紹

1.1.概念

高層模塊不能依賴於一個“具體化、細節化”的低層模塊,而是通過一個抽象的“規範/標準”建立兩者之間的依賴關係,簡言之就是:不依賴於實現,而是依賴於抽象。這裡“實現”一詞有的地方也稱為“細節”,在編碼中主要體現的是我們根據業務模型具體自定義的普通類,比如:員工類、商品類等。而其中的“抽象”一詞是指定的介面或抽象類。

 

1.2.高層與低層

下麵我們通過傳統的三層架構作為背景來理解“依賴倒置原則”中的高層與低層的含義。

在分層架構中,高層是相對而言的,對於上面三層架構圖中而言最高層是“表示層”,相對於“業務邏輯層”它的高層是“表示層UI”,相對於“數據訪問層”它的高層則是“業務邏輯層”。

低層同樣也是相對而言的,對於上面三層架構圖中而言最低層是“數據訪問層”,相對於“業務邏輯層”它的低層是“數據訪問層”,相對於“表示層”它的低層則是“業務邏輯層”。

那麼簡單來說高層就相對於一個使用者,低層就相當於一個被使用者。

 

1.3.依賴倒置原則在分層架構中的體現

在早期比較傳統的項目中,三層架構的分層通常都是上圖的形式:表示層直接依賴於一個具體實現、非抽象的業務邏輯層,業務邏輯層對下層的依賴同樣如此。這種分層實際上在依賴上就是違背了“依賴倒置原則”,因為它都是依賴的一些具體的實現,而非抽象。

那麼對於傳統的三層架構,使用了“依賴倒置原則”的思想,就可以發揮其中的優勢,使其易於維護和擴展。比如說你負責的某個項目的DAL層是使用SqlServer資料庫,而需求要變更為Mysql資料庫,如果使用了“依賴倒置原則”建立了抽象的規範,那麼你就可以在不影響其他層的情況下,單獨實現抽象規範就可以進行變更,這樣的變更對於“依賴於具體實現”改動是最小的。

1.4.依賴倒置原則體現的緩衝性

例如你寫了一個計算統計的程式,其中某個數值的計算比較複雜,你將演算法封裝成了一個具體實現類,作為比參數變數引入到計算統計的程式。由於第一次寫的演算法不是很理想,你後面會面臨嘗試更多新的演算法,這就意味著每個新演算法的使用,都要去“計算統計程式”中進行協調改動。

如果你在演算法設計之初就通過介面或抽象類建立一個演算法規範/標準,那麼計算統計程式通過介面或抽象類作為參數變數引入演算法對象就能起到一個緩衝性,也可以更好的支持演算法的迭代,利於程式擴展和優化。


2.通過代碼示例說明依賴倒置重要性

下麵通過兩種代碼示例來理解依賴倒置原則以及它的重要性,第一種介紹的是“未使用”依賴倒置原則的代碼,並描述在“未使用”依賴倒置原則會出現怎樣的利害關係。第二種則是針對第一種出現的問題使用依賴倒置原則對其進行改良,從而體現出依賴倒置原則的優勢。

2.1.示例一(依賴實現)

 1    //武器劍
 2     class Sword
 3     {
 4         //攻擊的方法
 5         public void Attack()
 6         {
 7             Console.WriteLine("使用劍進行刺殺");
 8         }
 9     }
10 
11     //游戲角色類
12     class GameRole
13     {
14         //使用武器
15         public void UseWeapon(Sword sword)
16         {
17             sword.Attack();
18         }
19     }
20 
21     internal class Program
22     {
23         static void Main(string[] args)
24         {
25             GameRole gameRole = new GameRole();
26             gameRole.UseWeapon(new Sword());
27         }
28     }

上面代碼中分別定義了兩個類,一個是游戲角色類另一個是劍類,游戲角色類其中有一個“使用武器”的方法,該方法需要傳入一個劍類的對象,並調用劍類中的攻擊方法。

這個示例使用了我們日常玩電子游戲來作為背景,玩過游戲的朋友應該知道,游戲的更新迭代也是習以為常的事情。如果游戲中使用了以上的代碼,並且游戲中的角色使用的武器經常會發生一些改變,那麼代碼中的游戲角色類要針對每一個新武器新增對應的使用方法。如果無法窮舉使用的武器,那我們將會寫N個使用新武器的方法。

方式一這種形式的代碼,實際上就是在依賴具體的實現,體現在使用武器的方法上,方法總是必須要傳入一個具體的武器類(劍、斧頭等),而不是依賴一個抽象的標準/規範。我們可以通過示例很直觀的看出來,這種依賴具體實現的代碼並不適應需求變化。接下來我們則通過使用依賴倒置原則來消除這種“被病”。

 

 2.2.示例二(依賴抽象)

 1     //武器介面
 2     public interface IWeapon
 3     {
 4         void Attack();
 5     }
 6 
 7     //武器劍
 8     class Sword : IWeapon
 9     {
10         public void Attack()
11         {
12             Console.WriteLine("使用劍進行刺殺");
13         }
14     }
15 
16     //斧頭
17     class Axe : IWeapon
18     {
19         public void Attack()
20         {
21             Console.WriteLine("使用斧頭進行劈砍");
22         }
23     }
24 
25     //游戲角色類
26     class GameRole
27     {
28         //使用武器
29         public void UseWeapon(IWeapon weapon)
30         {
31             weapon.Attack();
32         }
33 
34     }
35 
36 
37     internal class Program
38     {
39         static void Main(string[] args)
40         {
41             GameRole gameRole = new GameRole();
42             gameRole.UseWeapon(new Sword());
43             gameRole.UseWeapon(new Axe());
44         }
45     }

示例二基於依賴倒置原則對示例一進行改良,將多種武器抽象成了一個介面,並且根據武器種類現狀創建實現了“武器介面”的實現類(劍、斧頭),游戲角色類將多個使用不同武器的方法縮減成一個方法,該方法接收一個“武器介面”類型的實例對象(也就是實現了該介面的類)作為參數。

游戲角色類從原本依賴的具體武器轉變成依賴一個抽象武器(依賴具體類轉變為依賴介面),從而體現出了從依賴實現到依賴抽象的轉變。那麼此時不管游戲對角色使用的武器進行新增或刪減,“游戲角色類”不用做大量的改動變化,而是將這個變化單獨抽離了出去,作為了一個獨立的介面。而這個介面不在單單隻對游戲角色類服務,還可以用於其他的類(妖怪類、魔獸類等),從而降低了代碼的變化性和耦合性,且提高代碼的復用性。

 

2.3.示例總結

基於上面的兩個示例的分析對比,我們就應該更加謹記“依賴倒置原則”在編碼中的重要性,如果我們的代碼只是使用面向具體實現編程,那麼程式結構上並不能更好的適應變化,更好的擴展、更好的維護,大量的冗餘代碼會導致程式越來越臃腫。


3.總結

一開始學習“依賴倒置原則”的時候,在明白其中的含義和作用後,往往都在糾結這個“倒置”到底是什麼意思,它倒置的是個啥,如果感覺不搞懂總感覺差點意思。經過反覆的思考,我個人的理解是:將原本高層對低層依賴具體細節,顛倒反義,轉為依賴於抽象。

依賴倒置原則在面向對象編程和框架的設計上都廣泛運用,它其中主要的核心思想就是:面向介面編程,而不是面向具體實現編程。使用介面或抽象類的目的是制定好規範,而不涉及任何具體的操作,把展現細節的任務交給他們的實現類去完成。

知識改變命運
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 原文地址:Android8.0 後臺服務保活的一種思路 | Stars-One的雜貨小窩 項目中有個MQ服務,需要一直連著,接收到消息會發送語音,且手機要在鎖屏也要實現此功能 目前是使用廣播機制實現,每次MQ收到消息,觸發一次啟動服務操作邏輯 在Android11版本測試成功,可實現上述功能 步驟 ...
  • 前言 本篇是以 HarmonyOS 官網的基於 TS 擴展的聲明式開發範式文檔,頁面佈局與連接為基礎進行編寫。儘管原篇已非常精簡,但是作為初學者想要快速入門,使用 ets 方式實現出 List 佈局、Grid 佈局、數據連接及頁面跳轉功能,還是稍顯晦澀。所以筆者將原文進行整合,提取出其中的要點,以便 ...
  • 隨著市場愈發成熟,開發者從平衡收益和風險的角度開始逐步探索混合變現的優勢,內購+廣告就是目前市場上混合變現的主要方式之一。 對於混合變現模式,您是否有這樣的困惑: 如何判斷哪些用戶更願意看廣告、哪些用戶付費意願更高,更好地平衡內購和廣告? 在提升整體收入的基礎上,怎樣為用戶提供更好的產品體驗? HM ...
  • 問題描述: 工作中碰到這樣一種場景, WebApp 已經實現了IM即時通訊及基於WebRTC實現的音視頻會議,音視頻聊天。 也是半路接手的項目,項目整體是使用WKWebView套殼載入h5 頁面實現(後期過審還有很多路要走) 。 h5與原生交互的方案使用的javascriptCore(具體如何使用, ...
  • 今天的內容vue腳手架,越來越有內味了,也慢慢地開始有點難度了哈哈,但是沒有關係,慢慢學慢慢琢磨,我倒是感覺有點越來越像node了,不知道怎麼回事,這是要向後端發展的節奏啊 一.初始化Vue腳手架 1.說明 一般腳手架選擇最新版本 2.具體步驟 全局安裝vue/cli腳手架 切換到項目目錄,運行 v ...
  • 常用函數封裝 獲取某日期若幹個工作日後的日期 * 參數: * time: [String] 給定日期 yyyy-MM-dd * itervalByDay: [Number] 相隔工作日 * separator: [String] 年月日分隔符 * 返回: * rq:[String] 匹配的日期yyy ...
  • 某日,群里有這樣一個問題,如何實現這樣的表盤刻度: 這其實是個挺有意思的問題,方法也有很多。 單標簽,使用 conic-gradient 實現表盤刻度 最簡單便捷的方式,就是利用角向漸變的方式 conic-gradient,代碼也非常簡單,首先,我們實現一個重覆角向漸變: <div></div> d ...
  • 今天是對vue組件化的一個理解,最主要的單文件組件,然後就可以腳手架的學習了,本來昨晚就該上傳的,但是用的那個上傳博客園的Python腳本不行了,換了一個新的。 組件化讓我越來越感覺到框架的力量了 一.模塊與組件,模塊化與組件化 1.對組件的理解 如果以我們原來編寫一個網頁的方式 依賴關係混亂我就不 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...