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

来源: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
  • 分組和樹形結構是不一樣的。 樹形結構是以遞歸形式存在。分組是以鍵值對存在的形式,類似於GroupBy這樣的形式。 舉個例子 ID NAME SEX Class 1 張三 男 1 2 李四 女 2 3 王二 男 1 當以Sex為分組依據時則是 Key Value 男 1 張三 男 1 3 王二 男 1 ...
  • NetCore中將SQLServer資料庫備份為Sql腳本 描述: 最近寫項目收到了一個需求, 就是將SQL Server資料庫備份為Sql腳本, 如果是My Sql之類的還好說, 但是在網上搜了一大堆, 全是教你怎麼操作SSMS的, 就很d疼! 解決方案: 通過各種查找資料, 還有一些老哥的幫助, ...
  • 我的Notion Clowd.Squirrel Squirrel.Windows 是一組工具和適用於.Net的庫,用於管理 Desktop Windows 應用程式的安裝和更新。 Squirrel.Windows 對 Windows 應用程式的實現語言沒有任何要求,甚至無需服務端即可完成增量更新。 ...
  • 轉載請註明來源 https://www.cnblogs.com/brucejiao/p/16188865.html 謝謝! 轉載請註明來源 https://www.cnblogs.com/brucejiao/p/16188865.html 謝謝! 轉載請註明來源 https://www.cnblog ...
  • 1. Netty源碼研究筆記(3)——Channel系列 依舊是通過先縱向再橫向的研究方法,在開篇中,我們發現不管是Sever還是Client,最終的啟動是通過調用channel的對應方法來完成的,而這個動作實際在channel綁定的eventLoop中執行。 接下來,我們繼續EchoSever、E ...
  • 大家好,今天給大家介紹一款輕量、快速、穩定可編排的組件式規則引擎框架LiteFlow。 一、LiteFlow的介紹 LiteFlow官方網站和代碼倉庫地址 官方網站:https://yomahub.com/liteflow Gitee托管倉庫:https://gitee.com/dromara/li ...
  • 我使用Spring AOP實現了用戶操作日誌功能 今天答辯完了,復盤了一下系統,發現還是有一些東西值得拿出來和大家分享一下。 需求分析 系統需要對用戶的操作進行記錄,方便未來溯源 首先想到的就是在每個方法中,去實現記錄的邏輯,但是這樣做肯定是不現實的,首先工作量大,其次違背了軟體工程設計原則(開閉原 ...
  • 《零基礎學Java》 繪製幾何圖形 Java可以分別使用 Graphics 和 Graphics2D 繪製圖形,Graphics類 使用不同的方法繪製不同的圖形(drawLine()方法可f以繪製線、drawRect()方法用於繪製矩形、drawOval()方法用於繪製橢圓形)。 Graphics類 ...
  • 本期教程人臉識別第三方平臺為虹軟科技,本文章講解的是人臉識別RGB活體追蹤技術,免費的功能很多可以自行搭配,希望在你看完本章課程有所收穫。 ...
  • 很多人都喜歡使用黑色的主題樣式,包括我自己,使用了差不多三年的黑色主題,但是個人覺得在進行視窗轉換的時候很廢眼睛。 比如IDEA是全黑的,然後需要看PDF或者WORD又變成白色的了,這樣來回切換導致眼睛很累,畢竟現在網頁以及大部分軟體的界面都是白色的。那麼還是老老實實的使用原來比較順眼的模式吧。 1 ...