相關(guān)鏈接:
0. 設(shè)計(jì)模式之六大原則總結(jié)
1. 設(shè)計(jì)模式之單一職責(zé)原則
2. 設(shè)計(jì)模式之里式替換原則
3. 設(shè)計(jì)模式之依賴倒置原則
4. 設(shè)計(jì)模式之接口隔離原則
5. 設(shè)計(jì)模式之迪米特法則
6. 設(shè)計(jì)模式之開閉原則
1.1 定義
- 高層模塊不應(yīng)該依賴低層模塊,二者都應(yīng)該依賴其抽象;
- 抽象不應(yīng)該依賴細(xì)節(jié)座硕;
- 細(xì)節(jié)應(yīng)該依賴抽象
1.2 問題由來
類 A 直接依賴類 B,假如要將類 A 改為依賴類 C 图谷,則必須通過修改類 A 的代碼來達(dá)成主之。這種場景下酵幕,類 A一般是高層模塊衬以,負(fù)責(zé)復(fù)雜的業(yè)務(wù)邏輯缓艳;類 B 和類 C 是低層模塊,負(fù)責(zé)基本的原子操作泄鹏;假如修改類 A郎任,會(huì)給程序帶來不必要的風(fēng)險(xiǎn)。
1.3 解決方案
將類 A 修改為依賴接口 Interface1备籽,類 B 和類 C 各自實(shí)現(xiàn)接口 Interface2,類 A 通過接口 Interface1 間接與類 B 或者類 C 發(fā)生聯(lián)系,則會(huì)大大降低修改類 A 的幾率车猬。
1.4 具體分析
依賴倒置原則基于這樣一個(gè)事實(shí):相對(duì)于細(xì)節(jié)的多變性霉猛,抽象的東西要穩(wěn)定的多。以抽象為基礎(chǔ)搭建起來的架構(gòu)比以細(xì)節(jié)為基礎(chǔ)搭建起來的架構(gòu)要穩(wěn)定的多珠闰。抽象指的是接口或者抽象類惜浅,細(xì)節(jié)就是具體的實(shí)現(xiàn)類,(iOS 中可以理解為抽象就是協(xié)議伏嗜,細(xì)節(jié)是實(shí)現(xiàn)該協(xié)議的實(shí)現(xiàn)類)坛悉,使用接口或者抽象類的目的是制定好規(guī)范和契約,而不去涉及任何具體的操作承绸,把展現(xiàn)細(xì)節(jié)的任務(wù)交給他們的實(shí)現(xiàn)類去完成裸影。
依賴倒置原則的核心思想是面向接口編程,達(dá)到解耦的過程军熏。
1.5 舉例說明
我們用一個(gè)例子來說明面向接口編程相對(duì)于面向?qū)崿F(xiàn)編程好在什么地方轩猩。母親給孩子講故事,只要給她一本書荡澎,她就可以照著書給孩子講故事了均践,代碼如下:
class Book : NSObject{
func getContent() -> String {
return "在很久很久之前....";
}
}
class Mother : NSObject {
func narrate(book : Book) {
print("媽媽開始將故事");
print(book.getContent());
}
}
// 執(zhí)行的代碼
let mother = Mother()
mother.narrate(book: Book())
運(yùn)行結(jié)果:
媽媽開始講故事
很久很久以前有一個(gè)阿拉伯的故事……
1.6 舉例進(jìn)階
假如有一天,孩子長大了摩幔,需要了解國家大事了彤委,不是看書,而是看報(bào)紙了或衡,讓這位母親講一下報(bào)紙的新聞焦影,報(bào)紙的代碼如下:
class Newspaper : NSObject{
func getContent() -> String {
return "2020 年的春運(yùn)已經(jīng)開始了....";
}
}
但是,目前來說薇宠,這位母親辦不到啊偷办,因?yàn)?Mother 類里面只有一個(gè)narrate
方法,參數(shù)是Book
澄港,這時(shí)椒涯,還得需要母親學(xué)習(xí)如何讀報(bào)紙(修改 Mother 類的代碼,添加方法)回梧,需要修改 Mother 才能讀废岂,但是實(shí)際上都是文字啊,Mother 再去學(xué)習(xí)狱意,學(xué)啥昂?
假如以后需求變成雜志详囤、網(wǎng)頁呢财骨?還得需要不斷的修改 Mother镐作,這顯然不是好的設(shè)計(jì)。原因就是 Mohter與 Book 之間的耦合性太高了隆箩,必須降低他們之間的耦合度才行该贾。
我們以 iOS 為例,定義一個(gè)協(xié)議:讀物捌臊,只要是可以讀的都屬于讀物:
protocol IReader {
// 獲取讀物內(nèi)容
func getContent() -> String;
}
Mother類和接口 IReader 之間發(fā)生依賴關(guān)系杨蛋,而 Book 和 Newspaper 都屬于讀物的范疇,他們各自都去實(shí)現(xiàn) IReader 接口理澎,這樣就符合依賴倒置原則了逞力,代碼修改為:
class Book : NSObject, IReader{
func getContent() -> String {
return "在很久很久之前....";
}
}
class Newspaper : NSObject, IReader{
func getContent() -> String {
return "2020 年的春運(yùn)已經(jīng)開始了....";
}
}
class Mother : NSObject {
func narrate(reader : IReader) {
print("媽媽開始將故事");
print(reader.getContent());
}
}
1.7 舉例總結(jié)
這樣修改之后,無論以后想去看網(wǎng)頁糠爬、雜志寇荧,都不需要再修改 Mother 類了。這只是一個(gè)簡單的例子秩铆,實(shí)際情況中砚亭,代表高層模塊的 Mother 類將負(fù)責(zé)完成主要的業(yè)務(wù)邏輯,一旦需要對(duì)它進(jìn)行修改殴玛,引入錯(cuò)誤的風(fēng)險(xiǎn)極大捅膘。所以遵循依賴倒置原則可以降低類之前的耦合性,提高系統(tǒng)的穩(wěn)定性滚粟,降低修改程序造成的風(fēng)險(xiǎn)寻仗。
1.8 總結(jié)
采用依賴倒置原則給多人并行開發(fā)帶來了極大的便利,比如上例中凡壤,原本 Mother 類與 Book 類直接耦合時(shí)署尤,Mother 類必須等 Book 類編碼完成后才可以進(jìn)行編碼,因?yàn)?Mother 類依賴于 Book 類亚侠,修改后的程序則可以同時(shí)開工曹体,互不影響,因?yàn)?Mother 與 Book 類之間一點(diǎn)關(guān)系也沒有硝烂。參與協(xié)作開發(fā)的人越多箕别、項(xiàng)目越龐大,采用依賴倒置原則的意義就越重大滞谢。
在實(shí)際編程時(shí)串稀,我們一般需要做到如下 3 點(diǎn):
- 低層模塊盡量都要有抽象類或接口,或者兩者都有
- 變量的聲明類型盡量是抽象類或接口
- 使用繼承時(shí)遵循里式替換原則
依賴倒置原則的核心就是要我們面向接口編程狮杨,理解了面向接口編程母截,也就理解了依賴倒置。