這是理解solid
原則中,關於依賴倒置原則如何幫助我們編寫低耦合和可測試**的第一篇文章。
當我們在讀書,或者在和一些別的開發者聊天的時候,可能會談及或者聽到術語soild
。在這些討論中,一些人會提及它的重要性,以及乙個理想中的系統,應當包含它所包含的5條原則的特性。
我們在每次的工作中,你可能沒有那麼多時間思考關於架構這個比較大的概念,或者在有限的時間內或督促下,你也沒有辦法實踐一些好的設計理念。
但是,這些原則存在的意義不是讓我們「跳過」它們。軟體工程師應當將這些原則應用到他們的開發工作中。所以,在你每一次敲**的時候,如何能夠正確的將這些原則付諸於行,才是真正的問題所在。如果可以那樣的話,你的**會變得更優雅。
solid
原則是由5個基本的原則構成的。這些概念會幫助創造更好(或者說更健壯)的軟體架構。這些原則包含(solid
是這5個原則的開頭字母組成的縮略詞):
起初這些原則是robert c. martin在2023年提出的,遵循這些原則可以幫助我們更好的構建,低耦合、高內聚的軟體架構,同時能夠真正的對現實中的業務邏輯進行恰到好處的封裝。
不過這些原則並不會使乙個差勁的程式設計師轉變為乙個優秀的程式設計師。這些法則取決於你如何應用它們,如果你是很隨意的應用它們,那等同於你並沒有使用它們一樣。
關於原則和模式的知識能夠幫助你決定在何時何地正確的使用它們。儘管這些原則僅僅是啟示性的,它們是常見問題的常規解決方案。實踐中,這些原則的正確性已經被證實了很多次,所以它們應當成為一種常識。
這兩句話的意思是什麼呢?
一方面,你會抽象一些東西。在軟體工程和電腦科學中,抽象是一種關於規劃計算機系統中的複雜性的技術。它的工作原理一般是在乙個人與系統互動的複雜環境中,隱藏當前級別下的更複雜的實現細節,同時它的範圍很廣,常常會覆蓋多個子系統。這樣,當我們在與乙個以高階層面作為抽象的系統協作時,我們僅僅需要在意,我們能做什麼,而不是我們如何做。
另外,你會針對你的抽象,有一寫低階別的模組或者具體實現邏輯。這些東西與抽象是相反的。它們是被用於解決某些特定問題所編寫的**。它們的作用域僅僅在某個單元和子系統中。比如,建立乙個與mysql資料庫的連線就是乙個低階別的實現邏輯,因為它與某個特定的技術領域所繫結。
現在仔細讀這兩句話,我們能夠得到什麼暗示呢?
依賴倒置原則存在的真正意義是指,我們需要將一些物件解耦,它們的耦合關係需要達到當乙個物件依賴的物件作出改變時,物件本身不需要更改任何**。
這樣的架構可以實現一種松耦合的狀態的系統,因為系統中所有的元件,彼此之間都了解很少或者不需要了解系統中其餘元件的具體定義和實現細節。它同時實現了一種可測試和可替換的系統架構,因為在松耦合的系統中,任何元件都可以被提供相同服務的元件所替換。
但是相反的,依賴倒置也有一些缺點,就是你需要乙個用於處理依賴倒置邏輯的容器,同時,你還需要配置它。容器通常需要具備能夠在系統中注入服務,這些服務需要具備正確的作用域和引數,還應當被注入正確的執行上下文中。
舉個例子,我們可以在這個例子中學到更多關於依賴倒置的知識,我們將使用inversify.js
作為依賴倒置的容器,通過這個依賴倒置容器,我們可以看看如何針對提供websocket
連線服務的業務場景,提供服務。
比如,我們有乙個web伺服器提供websockets
連線服務,同時客戶端想要連線伺服器,同時接受更新的通知。當前我們有若干種解決方案來提供乙個websocket服務,比如說socket.io
、socks
或者使用瀏覽器提供的關於原生的websocket
介面。每一套解決方案,都提供不同的介面和方法供我們呼叫,那麼問題來了,我們是否可以在乙個介面中,將所有的解決方案都抽象成乙個提供websocket
連線服務的提供者?這樣,我們就可以根據我們的實際需求,使用不同的websocket服務提供者。
首先,我們來定義我們的介面:
export inte***ce websocketconfiguration
export inte***ce socketfactory
注意在介面中,我們沒有提供任何的實現細節,因此它既是我們所擁有的抽象。
接下來,如果我們想要乙個提供socket.io
服務工廠:
import from 'socket.io-client';
class socketiofactory implements socketfactory
}
這裡已經包含了一些具體的實現細節,因此它不再是抽象,因為它宣告了乙個從socket.io
庫中匯入的manager
物件,它是我們的具體實現細節。
我們可以通過實現socketfactory
介面,來增加若干工廠類,只要我們實現這個介面即可。
我們在提供乙個關於客戶端連線例項的抽象:
export inte***ce socketclient
然後再提供一些實現細節:
class websocketclient implements socketclient
public connect(config: websocketconfiguration): promise
return new promise((resolve, reject) => );
} public emit(event: string, ...args: any): promise
return this.socket.emit(event, args, (response: any) =>
return resolve();
});});
} public on(event: string, fn: function): promise
this.socket.on(event, fn);
resolve();
});} public close(): promise);
});}}
值得注意的是,這裡我們在建構函式中,傳入了乙個型別是socketfactory
的引數,這是為了滿足關於依賴倒置原則的第一條規則。對於第二條規則,我們需要一種方式來提供這個不需要了解內部實現細節的、可替換的、易於配置的引數。
這也是為什麼我們要使用inversify
這個庫的原因,我們來加入一些額外的**和註解(裝飾器):
import from 'inversify';
const websocketfactorytype: symbol = symbol('websocketfactory');
const websocketclienttype: symbol = symbol('websocketclient');
let types: any = ;
@injectable()
class socketiofactory implements socketfactory
...@injectable()
class websocketclient implements socketclient
這些注釋(裝飾器)僅僅會在**執行時,在如何提供這些元件例項時,提供一些元資料,接下來我們僅僅需要建立乙個依賴倒置容器,並將所有的物件按正確的型別繫結起來,如下:
import from 'inversify';
import 'reflect-metadata';
const provider = new container();
// bindings
provider.bind(types.websocketclient).to(websocketclient);
provider.bind(types.websocketfactory).to(socketiofactory);
export default provider;
讓我們來看看我們如何使用我們提供連線服務的客戶端例項:
var socketclient = provider.get(types.websocketclient);
當然,使用inversify
可以提供一些更簡單易用的繫結,可以通過瀏覽它的**來了解。
一般說到依賴倒置原則,往往第乙個想到的術語即是依賴注入
,這種在各個技術棧都有應用,之後又會馬上想到spring
、ng
等前後端框架。
我們確實是通過使用這些框架熟知這個概念的,但是如果你仔細想想的話,是否還有其他的一些場景也使用了類似的概念呢?
比如: 也許有的人會不同意我的觀點,會說依賴注入一般都是面向類和介面來講的,這確實有一定的道理,但是我認為沒有必要侷限在一種固定的模式中去理解依賴倒置,畢竟它是一種思想,一種模式,在js中,所有的東西都是動態的,函式是一等公民,是物件,那麼把這些與依賴倒置原則聯絡起來,完全也講的通。我們真正關心的是核心問題是如何解耦,把更多的注意力投入的真正的業務邏輯中去。
依賴倒置原則
依賴倒置原則 為什麼會出現這個原則呢?q 所有的一切都源於變化,現在orm足夠強大了,看一下他的原始碼也會發現,工廠 介面的使用都是為了更好的擴充套件。舉個簡單的例子 你的老師讓你寫了乙個 豬 類,實現了他的移動方法,如下 public class pig public class client 第...
依賴倒置原則
1 抽象不應該依賴於具體,具體應該依賴於抽象。2 高層次模組不應該依賴於低層次模組,它們都應該依賴於抽象。對於乙個小賣部來說,有許多飲料,比如可樂 雪碧 橙汁 這時,我們把小賣部定義為乙個具體類,如果我們沒有選擇依賴倒置原則的話,我們就應該在小賣部中new coke new sprit new or...
依賴倒置原則
依賴倒置原則 說白了就是 針對介面程式設計。case 比如在 unity 中,為了使常用 可以復用,會把許多函式寫成程式集,每次做新專案的時候直接呼叫這些函式就可以。也是高層模組依賴低層模組 資源載入,當前專案是使用 resoucers 方式載入的 class resourcemanager 有一天...