03.依賴倒置原則(Dependence Inversion Principle)

概述

高層模塊不應依賴低層模塊,二者都應該依賴其抽象。而抽象不應依賴細節,細節應該依賴抽象。依賴倒置原則的中心思想其實就是面向接口編程
相對于細節的多變性,抽象的東西會穩定的多,所以以抽象為基礎搭建的架構自然也會比以細節為基礎搭建的架構穩定的多
使用接口或抽象類的目的是為了更好的制定規范,而不涉及任何具體的操作,把展現細節的任務交給他們的實現類去完成。

相信有讀過spring framework源碼的同學應該對這一點深以為是,比如其核心接口之一的BeanFactory接口之下就繼承了AutowireCapableBeanFactory、HierarchicalBeanFactory、ListableBeanFactory接口,而這些接口又被多個抽象類有選擇實現,正是對依賴倒置原則的應用才使得spring framework 框架具有了極高的健壯性和擴展性。
在這里插入圖片描述

三寸反骨

我們不妨從相反的角度出發,寫個反例看看會有什么問題,今日反骨頗重,就是不想遵循依賴倒置原則。
比如我們現在需要編寫一個簡單的Person類,讓他可以接受郵件消息即可。
反例

public class DependecyInversion {public static void main(String[] args) {Person person = new Person();person.receive(new Email());}
}class Email{public String getInfo(){return "電子郵件信息: Hello,Email";}
}class Person {public void receive(Email email){System.out.println(email.getInfo());}
}

編程的過程十分愉快,如此簡單的需求甚至不需要聰明的我們多思考一秒。運行效果也完全滿足預期。
但是,來了一個不好不壞的消息:“能力需要擴展,客戶要求,除了收到email的能力外,微信消息也想收到!”
“反骨仔想了想,不要緊,我新增類,同時Person類也要增加相應的方法就好了呀”!
于是他加班1小時完成了這個需求,自信滿滿的走了。
但是,第二天又來了個不好不壞的消息:“客戶對產品很滿意,同時要求除了想收到email、微信消息之外,還想擴展幾十個軟件的消息,清單包含:“QQ、微博、墨跡天氣、釘釘…”
反骨仔爆炸了,因為這個需求如果繼續按他的思路去實現,類也爆炸了。實現的方法更是爆炸到難以維護。
所以說一定要設計先行,一個優秀的設計可能會占據相當長的開發時間,但是會為后期的擴展和維護提供強有力的保障!


優化設計

我們把時間推回兩天前,接到需求的我們首先便進行了深度剖析并達成了共識:“依賴倒置原則必須遵守!”于是,有了如下代碼:

public class DependecyInversion {public static void main(String[] args) {Person person = new Person();person.receive(new Email());person.receive(new WeChat());}
}
interface IReceive{public String getInfo();
}class Email implements IReceive{public String getInfo(){return "電子郵件信息: Hello,Email";}
}class WeChat implements IReceive{public String getInfo(){return "微信信息: Hello,WeChat";}
}class Person {public void receive(IReceive receiver){System.out.println(receiver.getInfo());}
}

當客戶說我要繼續擴展幾十個消息入口時,我們會發現,我們對于person類不需要做任何改動了,不過是需要遵照IReceive接口規范去實現新擴展的業務細節就可以了。善莫大焉。


依賴關系傳遞三板斧

常見的依賴關系傳遞有三種方式:

接口傳遞

public class DependencyPass {public static void main(String[] args) {ChangHong changHongTv = new ChangHong();OpenAndClose openAndClose = new OpenAndClose();openAndClose.open(changHongTv);}
}class ChangHong implements ITV,ITV2,ITV3{@Overridepublic void play() {System.out.println("長虹電視機打開了。");}
}
interface IOpenAndClose{public void open(ITV tv);
}
interface ITV{public void play();
}
//實現接口
class OpenAndClose implements IOpenAndClose{@Overridepublic void open(ITV tv) {tv.play();}
}

構造方法傳遞

public class DependencyPass {public static void main(String[] args) {ChangHong changHongTv = new ChangHong();OpenAndClose2 openAndClose2 = new OpenAndClose2(changHongTv);openAndClose2.open();}}
class ChangHong implements ITV,ITV2,ITV3{@Overridepublic void play() {System.out.println("長虹電視機打開了。");}
}
interface IOpenAndClose2{public void open();
}
interface  ITV2{public void play();
}
class OpenAndClose2 implements IOpenAndClose2{public ITV2 tv;public OpenAndClose2(ITV2 tv){this.tv = tv;}@Overridepublic void open() {this.tv.play();}
}

setter方法傳遞

public class DependencyPass {public static void main(String[] args) {ChangHong changHongTv = new ChangHong();OpenAndClose3 openAndClose3 = new OpenAndClose3();openAndClose3.setTv(changHongTv);openAndClose3.open();}}class ChangHong implements ITV,ITV2,ITV3{@Overridepublic void play() {System.out.println("長虹電視機打開了。");}
}
interface IOpenAndClose3{public void open();public void setTv(ITV3 itv3);
}
interface ITV3{public void play();
}
class OpenAndClose3 implements IOpenAndClose3{private ITV3 itv3;@Overridepublic void setTv(ITV3 itv3) {this.itv3 = itv3;}@Overridepublic void open() {this.itv3.play();}
}

  1. 底層模塊盡量都要有抽象類或接口,或者兩者都有,程序穩定性更好;
  2. 變量的聲明類型盡量是抽象類或接口,這樣我們的變量引用和實際對象間就存在一個緩沖層,利于程序擴展和優化;
  3. 繼承時遵循里氏替換原則;
  4. 什么是里氏替換原則?下次講!

關注我,共同進步,每周至少一更。——Wayne

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/167393.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/167393.shtml
英文地址,請注明出處:http://en.pswp.cn/news/167393.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

EMG肌肉電信號處理合集(二)

本文主要展示常見的肌電信號特征的提取說明。使用python 環境下的Pysiology計算庫。 目錄 1 肌電信號第一次burst的振幅, getAFP 函數 2 肌電信號波長的標準差計算,getDASDV函數 3 肌電信號功率譜頻率比例,getFR函數 4 肌電信號直方圖…

Day41:198.打家劫舍、213.打家劫舍II、337.打家劫舍 III

文章目錄 198.打家劫舍思路代碼實現 213.打家劫舍II思路代碼實現 337.打家劫舍 III思路代碼實現記憶化遞歸法(其他解法) 198.打家劫舍 題目鏈接 思路 確定dp數組(dp table)以及下標的含義 dp[i]:考慮下標i以內的房屋…

華清遠見嵌入式學習——網絡編程——小項目

項目要求&#xff1a; 代碼實現&#xff1a; 服務器端&#xff1a; #include <myhead.h>//定義協議包 struct proto {char type;char name[20];char text[128]; };int main(int argc, const char *argv[]) {//判斷從終端輸入的字符串的個數if(argc ! 3){printf("…

mysql中TIMESTAMP 和DATETIME數據類型的區別

在MySQL中&#xff0c;TIMESTAMP和DATETIME都用于表示日期和時間&#xff0c;但是它們之間存在一些關鍵區別。下面我們通過幾個關鍵點來詳細了解這兩種數據類型的使用&#xff1a; 存儲范圍 TIMESTAMP類型的存儲范圍從1970-01-01 00:00:01 UTC到2038-01-19 03:14:07 UTC。DAT…

Django之importlib模塊

【1】介紹 import importlib importlib模塊是Python中用于動態加載和導入模塊的內置模塊 它提供了一組函數和類&#xff0c;使得我們可以在運行時根據需要加載模塊&#xff0c;并且可以對已導入的模塊進行操作和管理 【2】importlib模塊中的import_module方法 【2.1】導入模塊…

無需API開發,錢方QFPay連接營銷系統和廣告推廣平臺

隨著電子商務市場的不斷發展&#xff0c;企業需要集成各種業務系統&#xff0c;以提高業務效率和降低運營成本。錢方QFPay提供了一種創新的解決方案&#xff0c;幫助企業實現系統間的連接和集成&#xff0c;無需進行復雜的API開發。除了電商系統和客服系統&#xff0c;錢方還能…

武漢光庭公司地圖引擎開發工程師24秋招三場面試完整流程

本文介紹2024屆秋招中&#xff0c;武漢光庭信息技術股份有限公司的智能駕駛地圖引擎開發工程師崗位一面、二面、三面的面試基本情況、提問問題等。 10月投遞了武漢光庭信息技術股份有限公司的智能駕駛地圖引擎開發工程師崗位&#xff0c;暫時并不清楚所在的部門。目前完成了全部…

mysql:修改密碼的幾種方式

背景 當我們 brew install mysql 新安裝 mysql 的時候&#xff0c;是沒有密碼的&#xff0c;我們可以直接通過 mysql -u root 連接上。但是密碼還是要設置的&#xff0c;一是為了安全&#xff0c;二是有些數據庫軟件如 Sequel 連接都是必須要密碼的&#xff0c;接下來我們來看…

電磁建模的分布式并行計算技術

本文提出了一種新的分布式并行電磁建模技術&#xff0c;以加快電磁結構的神經網絡建模過程。現有的電磁建模技術通常需要反復改變微波器件的參數&#xff0c;驅動電磁模擬器以獲得足夠的訓練和測試樣本。隨著電磁建模問題復雜性的增加&#xff0c;由于單臺計算機的性能有限&…

DP好題總結

LCIS最長公共上升子序列 題解&#xff1a;https://blog.csdn.net/weixin_50624971/article/details/116892236 概括&#xff1a; 決策優化DP 考慮LCS可以寫成 O ( n 4 ) O(n^4) O(n4) 的如果我們把狀態設為 f [ i , j ] f[i,j] f[i,j] 表示考慮到 a [ i ] , b [ j ] a[i]…

機器學習【00】pycharm使用遠程服務器

我們使用conda在服務器上創建虛擬環境&#xff0c;遠程使用pycharm進行編程 pycharm版本2023.1.3 一.首先在服務器上創建虛擬環境 注&#xff1a;anaconda的安裝可以參考ubuntu系統miniconda的安裝 conda create --name tac python3.7二.pycharm 連接 點擊add interpreter …

查企業聯系電話的方法

對于銷售來說&#xff0c;獲取準確、全面的企業聯系方式&#xff0c;無疑是開發客戶的基礎與保障&#xff0c;因為任憑能力再高&#xff0c;說服能力多強&#xff0c;沒有與客戶接觸的機會&#xff0c;這些都是無稽之談。但是大家都知道&#xff0c;道理都懂&#xff0c;但是要…

.yaml文件的簡介

文章目錄 YAML文件簡介YAML文件的示例 YAML文件簡介 YAML是一種人類可讀的數據序列化標準。它常被用于配置文件、數據交換格式、以及在一些編程語言中的數據結構描述。 YAML 文件的主要特點有如下四點&#xff1a; 可讀性&#xff1a;YAML 的語法結構簡潔明了&#xff0c;容…

報錯AttributeError: module ‘cv2‘ has no attribute ‘ximgproc‘

報錯AttributeError: module ‘cv2’ has no attribute ‘ximgproc’ 首先查看是否安裝opencv-contrib-python pip list | grep opencv顯示 opencv-contrib-python 4.4.0.46 opencv-python 4.8.1.78 opencv-pyt…

【2023.11.24】Mybatis基本連接語法學習?

基本配置 1.如果使用Maven管理項目&#xff0c;需要在pom.xml中配置依賴。 2.安裝Mybatis-3.5.7.jar包 3.進行XML配置&#xff1a;這里將文件命名為mybatis-config.xml 配置數據庫連接XML文件 <?xml version"1.0" encoding"UTF-8" ?> <!DO…

Crypto(10)BUUCTF-RSA3(共模攻擊)

一.共模攻擊的現實意義 好奇一個問題&#xff0c;即共模攻擊有什么現實意義&#xff1f; 發現也沒有什么現實意義&#xff0c;因為&#xff08;n,e&#xff09;是已知的&#xff0c;通常每個用戶的n是不同的&#xff0c;除非特殊情況吧 二.共模攻擊的數學原理&#xff1a; 通…

最重要的BI測試-適用于任何BI和分析平臺

為什么 BI 測試是答案 相信你的數據可視化是成功執行商業智能 (BI) 和分析項目的關鍵因素。我敢肯定&#xff0c;你遇到過以下情況&#xff1a;業務主管或業務用戶反饋說他們的分析看起來不對&#xff0c;他們的 KPI 看起來有問題&#xff0c;或者速度太慢而無法使用。要問自己…

SQL 通配符:用于模糊搜索和匹配的 SQL 關鍵技巧

SQL通配符字符 通配符字符用于替代字符串中的一個或多個字符。通配符字符與LIKE運算符一起使用。LIKE運算符用于在WHERE子句中搜索列中的指定模式。 示例 返回所有以字母 ‘a’ 開頭的客戶&#xff1a; SELECT * FROM Customers WHERE CustomerName LIKE a%;通配符字符 符…

5:kotlin 類(Classes )

kotlin支持面向對象編程&#xff0c;也有雷和對象的概念 要聲明一個類需要使用class關鍵字 class Customer屬性&#xff08;Properties&#xfeff;&#xff09; 可以在類名后邊添加()&#xff0c;在()里邊聲明屬性 class Contact(val id: Int, var email: String)聲明了不…

單片機、ARM、嵌入式開發、Android 底層開發有什么關系?

單片機、ARM、嵌入式開發、Android 底層開發有什么關系&#xff1f; 從我目前的見識來看&#xff1a; 單片機是個系統&#xff08;比如&#xff1a;51、AVR、PLC...&#xff09;&#xff0c;其中包含了去除了輸入輸出之外的運算器、控制器、存儲器&#xff0c;我們用程序可以非…