領域驅動設計第三節-戰術設計(中上)

層與層之間的協作

在固有的認識中,分層架構的依賴都是自頂向下傳遞的,這也符合大多數人對分層的認知模型。

從抽象層次來看,層次越處於下端就會越通用越公用,與具體的業務隔離的越遠。

出於重用的考慮,這些通用和公共的功能往往會被單獨剝離出來形成平臺或架構,在系統邊界內的底層除了面向高層提供足夠的實現外,就都成了平臺或架構的調用者。

就是說越是通用的層,越有可能與外部平臺或框架形成強依賴。若依賴的傳遞方向仍然採用自頂向下,就會導致系統的業務對象也隨之依賴於外部平臺或框架。

依賴倒置原則提出了對這種自頂向下依賴的挑戰,它要求"高層模塊不應該依賴於底層模塊,二者都應該依賴於抽象”。

這個原則正本清源,給了我們嚴重的警告-----誰規定在分層架構中,依賴就一定要沿着自頂向下的方向傳遞呢、

平時常理解依賴,是因爲被依賴方需要爲依賴放(調用者)提供功能支持,這是從功能重用的角度考慮的。

但也不能忽略變化對系統產生的影響!與建造房屋一樣,分層的模塊需要構建在穩定的模塊之上,誰更穩定呢?

抽象更穩定。因此,依賴倒置原則隱含的本質就是:我們要依賴不變或穩定的元素(類,模塊或層),

也就是該原則的第二句話:抽象不應該依賴於細節,細節應該依賴於抽象

這一原則實際上是面向接口設計原則的體現,即針對接口編程,而不是針對實現編程。

高層模塊對底層模塊的實現是一無所知的,帶來的好處是:

底層模塊的細節實現可以獨立變化,避免變化對高層模塊產生污染

在編譯時,高層模塊可以獨立於底層模塊單獨存在

對於高層模塊而言,底層模塊的實現是可以替換的

倘若高層依賴於底層的抽象,必然會面臨一個問題:如何把具體的實現傳遞給高層的類?

由於在高層通過接口隔離了對具體實現的依賴,就意味着這個具體依賴被轉移到了外部,究竟使用哪一種具體實現,由外部調用者決定。

只有在運行調用者代碼時,纔將外面的依賴傳遞給高層的類。

我們將這種機制稱之爲:依賴注入(Dependency injection)

爲了更好地解決高層對底層的依賴,需要將依賴倒置原則與依賴注入結合起來。

層之間的協作並不一定是自頂向下的傳遞通信,也有可能是自底向上通信。

例如,在 CIMS(計算機集成製造系統)中,往往會由低層的設備監測系統監測(偵聽)設備狀態的變化。

當狀態發生變化時,需要將變化的狀態通知到上層的業務系統。

如果說自頂向下的消息傳遞往往被描述爲“請求(或調用)”,則自底向上的消息傳遞則往往被形象地稱之爲“通知”。

倘若我們顛倒一下方向,自然也可以視爲這是上層對下層的觀察,故而可以運用觀察者模式(Observer Pattern),在上層定義 Observer 接口,並提供 update() 方法供下層在感知狀態發生變更時調用;

或者,我們也可以認爲這是一種回調機制。雖然本質上這並非回調,但設計原理是一樣的。 

如果採用了觀察者模式,則與前面講述的依賴倒置原則有差相彷彿之意,因爲下層爲了通知上層,需要調用上層提供的 Observer 接口。

如此看來,無論是上層對下層的“請求(或調用)”,抑或下層對上層的“通知”,都顛覆了我們固有思維中那種高層依賴低層的理解。

我們對分層架構有了更清醒的認識時我們就必須要打破那種談分層架構必爲經典三層架構又或領域驅動設計推薦的四層架構這種固有思維,而是將分層視爲關注點分離的水平抽象層次的體現。

既然如此,架構的抽象層數就不是固定的,甚至每一層的名稱也未必遵循固有(經典)的分層架構要求。

設計系統的層需得結合該系統的具體業務場景而定。

當然,我們也要認識到層次多少的利弊:過多的層會引入太多的間接而增加不必要的開支,層太少又可能導致關注點不夠分離,導致系統的結構不合理。

我們還需要正視架構中各層之間的協作關係,打破高層依賴低層的固有思維,從解除耦合(或降低耦合)的角度探索層之間可能的協作關係。

另外,我們還需要確定分層的架構原則(或約束),例如是否允許跨層調用,即每一層都可以使用比它低的所有層的服務,而不僅僅是相鄰低層。這就是所謂的“鬆散分層系統(Relaxed Layered System)

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章