前言
注: 當我在學習DDD時,看到其中的六邊架構,在初步瞭解其架構思想之後,就深深地被吸引了,因為它可以解決諸多我在專案中遇到的問題。
這裡將著重介紹六邊形架構的思想,以及其解決的問題,並不與其它架構做深入的對比。
六邊形架構 又被稱之為ports&adpers(我認為這個名稱更合適),是 Cockburn在2005年提出的,目的是為了解決業務邏輯與輸入輸出的解耦。
架構思想
想像一下電腦如何與周邊裝置如何互動的:
周邊裝置有耳機、鍵盤、外接顯示器、耳機等,它們通過電腦的USB、HDMI等埠進行連線;但有時剛買來一個新的裝置(比如印表機),想通過USB與電腦連線,但你插上時,電腦卻提示你無法識別,需要安裝驅動,你按照說明,安裝好驅動就可以使用了。而且比較神奇的是,我有兩個滑鼠,一個是ps/2介面,一個是USB介面,但插上去都可以用, 這是因為系統中安裝了兩種介面型別的驅動(介面卡)。
通過上面的描述,我們知道,電腦與周邊裝置是通過埠與驅動(介面卡)互動的,且只需要有相應的驅動,埠可以和不同的裝置進行互動。
我們在設計架構和編碼過程中經常犯一個錯誤,將業務邏輯與外部實體間的互動糾纏在一起。比如,在分層架構中,對資料庫的訪問和外部介面的訪問通常放在gateway中,而由於分層構架,只做了業務的職現劃分,並未做層次的解耦,造成對於外部的訪問成了業務邏輯的核心;同樣,對於對外提供的介面,封裝在controller中,也是同樣的道理。(當然,這裡並不是說分層架構不好,只是處理問題的角度不同)。
六邊形架構關注的是“外部”和“內部”的差別,內部業務邏輯(Application)與外設(APP,WEB,資料庫等)完全隔離,僅通過Adapter 進行互動。
那Adapter起什麼作用呢?它負責將與外設互動的資料(包括命令、query)轉化為Application可以理解的資訊(業務module),並通過內部系統提供的介面進行業務邏輯的處理。
說了那麼多adpter,那port該如何界定其職責呢? 我們知道,電腦上埠定義了裝置的通訊協議,只要是相同的埠,無論是什麼裝置必須遵循這個協議,只是其通訊的內容可能有所不同。對於軟體系統來講,port上埠協議的體現就是api,即業務系統對外暴露的介面,一個埠可以有多個介面卡。比如一個系統提供產口的資訊的展示,這時候該資訊可能需要在app,web或者作為遠端服務對外提供產品資訊,這時候由Application是提供一個query 介面,並返回一個Product物件,至於要將其轉換成app,web或者遠端服務json格式,則由adapter來完成。
為什麼它叫六邊形架構呢?六邊形的一個邊就代表一個埠,但並不代表一個六邊型架構就必須有6個埠,其實這和六個邊沒有任何關係,作者只是為了方便表達自己的思想,將架構畫成了六邊形,也方便使用者能夠在業務架構時,更方便的設計。
這裡還是提醒一下,雖然六邊形強調內部和外部的區別,但並不代表我們不關注外部介面的主被動(對外提供服務,還是呼叫外部服務),但我們可以在實現埠和adapters 時,通過技術來遮蔽這種差異,但卻不適合,也沒必要使用一個完全相同的埠來遮蔽這種差異。所以一般的六邊形架構架構會在左右兩端各有埠,左邊代表對外提供服務,右邊代表呼叫外部服務。
通過上面的介紹,相信你已經瞭解了六邊形的設計思想。那它這種業務邏輯和外部系統的分離,還給我們帶來什麼好處呢?
如上圖所示,應用外對提供了兩個埠,使用者側API和資料側API。使用者側API,通過四個介面卡為app,http,GUI,ie提供服務;資料側通過兩個介面卡(DB和mock)為應用提供適配服務。大家看到這裡,可能會有些吃驚,怎麼還有mock?
是的,只需要實現data-side埠的的服務都可以為Application提供資料,對系統來說並不會感知到服務的差異,也就是說mock和db 可以提供無差異的服務。說到這裡你就明白了,再也不用將測試用例嵌入到業務邏輯中了,只要實現相應的adapter就可以了,再也不用因為業務程式碼的變動而更改測試用例。為整合化測試提供了很大的方便。
稍後我會補充一個專案案例!!!!
http://alistair.cockburn.us/Hexagonal+architecture