分層
分層相對重要,架構在設計中要考慮分層,其核心仍然是資源+服務+應用的三大層,這樣的分層仍然是SOA參考架構的核心思想。平臺+應用更多地只是上面分層模式的一個變形。分層的目的是透過分層理清整個應用的構建過程,並保證了各層之間的獨立設計和松耦合。
分層架構的一個重要原則是每層只能與位於其下方的層發生耦合。分層架構可以簡單分為兩種,即嚴格分層架構和鬆散分層架構。
在嚴格分層架構中,某層只能與位於其直接下方的層發生耦合;在鬆散分層架構中,則允許某層與它的任意下方層發生耦合。
分層架構的好處是顯而易見的。首先,層間鬆散的耦合關係使得我們可以專注於本層的設計,而不必關心其他層的設計,也不必擔心自己的設計會影響其他層,對提高軟體質量大有裨益。其次,分層架構使得程式結構清晰,升級和維護都變得十分容易,要更改某層的具體實現程式碼時,只要本層的介面保持穩定,對其他層就可以不必修改。即使本層的介面發生變化,也隻影響相鄰的上層,修改工作量小且錯誤可以控制,不會帶來意外的風險。
要保持程式分層架構的優點,就必須堅持各層間的鬆散耦合關係。在設計程式時,應該先劃分出可能的層次,以及此層次提供的介面和需要的介面。在設計某層時,應該儘量保持層間的隔離,僅使用下層提供的介面。
分層架構的優點如下。
◎ 開發人員可以只關注某一層。
◎ 可以很容易地用新的實現來替換原有層的實現。
◎ 可以降低層與層之間的依賴。
◎ 有利於標準化。
◎ 有利於各層邏輯的複用。分層架構的缺點如下。
◎ 因為增加了中間層,所以降低了系統的效能,不過可以透過快取機制來改善。
◎ 可能會導致級聯的修改。這種修改尤其體現在自上而下的方向,不過可以透過依賴倒置來改善。
模式模式是所有思維模式裡面的一個重點,架構模式是一個通用的、可重用的解決方案,架構設計中的模式匹配就是將最終的業務域問題匹配到對應的技術實現上,即根據業務需求來挑選最適合的技術,而不是用主流和最先進的技術去反推業務。
架構設計模式一般有分層模式、客戶端-伺服器模式、主從裝置模式、管道-過濾器模式、代理模式、P2P 模式、事件匯流排模式、MVC 模式、黑板模式和直譯器模式,接下來簡單介紹這些模式。
分層模式
分層架構的一個重要原則是每層只能與位於其下方的層發生耦合。分層架構可以簡單分為兩種:嚴格分層架構和鬆散分層架構。在嚴格分層架構中,其中一層只能與其直接下方的層發生耦合;在鬆散分層架構中,則允許某層與它的任意下方層發生耦合,並且要保持程式分層架構的優點,就必須堅持層間的松耦合關係。在設計程式時,應該先劃分出可能的層次,以及此層次提供的介面和需要的介面。在分層設計時,儘量保持層間的隔離,上層呼叫下層服務只能透過介面來實現。四層架構、五層架構和六邊形架構是領域驅動設計分層架構中比較經典的三種架構,下面分別對這3種架構進行講解。
1.四層架構
四層架構的模式如圖4.5所示。
圖4.5
對如圖4.5所示的各層解釋如下。
◎ 展示層:展示使用者請求返回的資料。使用者可以是一個系統,不一定是使用使用者介面的人。
◎ 應用層:定義系統需要完成的任務,並且指揮表達領域概念的物件來解決問題。這一層所負責的工作對業務來說意義重大,也是其他系統的應用層進行互動的必要渠道。應用層要儘量簡單,不包含業務規則或者知識,只為下一層中的領域物件協調任務、分配工作,使它們互相協作。它沒有反映業務情況的狀態,卻可以具有另外一種狀態,為使用者或程式顯示某個任務的進度。
◎ 領域層:負責表達業務概念、業務狀態資訊及業務規則。儘管儲存業務狀態的技術細節是由基礎設施層實現的,但是反映業務情況的狀態是由本層控制並且使用的。領域層是業務軟體的核心,領域模型位於這一層。
◎ 基礎設施層:向其他層提供通用的技術能力:為應用層傳遞訊息,為領域層提供持久化機制,為展示層繪製螢幕元件等。基礎設施層還能夠透過架構框架來支援4個層之間的互動模式。
2.五層架構
五層架構的模式如圖4.6所示。
圖4.6
對如圖4.6所示的各層解釋如下。
◎ 展示層:主要用於處理使用者傳送的Restful請求和解析使用者輸入的配置檔案等,並將資訊傳遞給應用層的介面。
◎ 應用層:負責多程序管理及排程、多執行緒管理及排程、多協程排程和維護業務例項的狀態模型。在排程層收到展示層的請求後,委託環境層與本次業務相關的上下文進行處理。
◎ 環境層:以上下文為單位,將領域層的領域物件轉換成合適的角色,透過角色互動起來完成業務邏輯。
◎ 領域層:定義領域模型,不僅包括領域物件及其之間關係的建模,還包括物件角色的顯式建模。
◎ 基礎設施層,向其他層提供通用的技術能力,例如業務平臺、程式設計框架、持久化機制、訊息機制、第三方庫的封裝和通用演算法,等等。
3.六邊形架構
六邊形架構,又被稱為埠和介面卡風格,最早由AlistairCockburn提出,並在領域驅動設計社群得到了發展和推廣。這個架構之所以是六邊形形式的,是為了凸顯這個架構的扁平,每個邊界的權重都是相等的。
六邊形架構的模式如圖4.7所示。
圖4.7
我們知道,經典分層架構分為三層(展示層、應用層和資料訪問層),而六邊形架構可以分成另外的三層,如下所述。
◎ 領域層(Domain Layer):最內層,是純粹的核心業務邏輯,一般不包含任何技術實現或引用。
◎ 埠層(Ports Layer):位於領域層之外,負責接收與用例相關的所有請求,這些請求負責在領域層中協調工作。埠層在埠內部作為領域層的邊界,在埠外部則扮演了外部實體的角色。
◎ 介面卡層(Adapters Layer):位於埠層之外,負責以某種格式接收輸入及產生輸出。比如,對於 HTTP 使用者請求,介面卡會將其轉換為對領域層的呼叫,並將領域層傳回的響應進行封裝,透過HTTP 傳回呼叫的客戶端。在介面卡層不存在領域邏輯,它的唯一職責就是在外部世界與領域層之間進行技術性的轉換。介面卡能夠與埠的某個協議關聯並使用該埠,多個介面卡可以使用同一個埠,在切換到某種新的使用者介面時,可以讓新介面與老介面同時使用相同的埠。
這樣做的好處是使業務邊界更加清晰,從而獲得更好的擴充套件性,還使業務複雜度和技術複雜度分離,是領域驅動設計的重要基礎。核心的領域層可以專注於業務邏輯而不用理會技術依賴,外部介面在被消費者呼叫時也不用關心業務在內部是如何實現的。正如上文提到的,六邊形架構的出現早於領域驅動設計,要實現領域驅動設計也不必非要採用六邊形架構,只是這種架構正好契合了領域驅動設計所需的條件,從六邊形架構出發,可以更容易理解領域驅動設計的思想。如圖4.7所示,介面卡所在的線框表示限界上下文,中間的六邊形表就是應用服務,標記出核心領域模型對外暴露的功能和方法。應用層的核心就是領域模型,包含領域物件和領域服務,其中領域物件又分為實體物件和值物件,值物件中的一個特定物件就是聚合根,聚合根就是這個領域的核心。
分層模式主要用於一般的桌面應用程式和電子商務We b應用程式。
客戶端-伺服器模式
客戶端-伺服器模式簡稱C/S結構,是一種網路架構,它將客戶端(Client)與伺服器(Server)區分開來。每個客戶端軟體的例項都可以向一個伺服器或應用程式伺服器傳送請求。客戶伺服器模式透過不同的途徑應用於很多不同型別的應用程式,最常見的就是目前網際網路上的網頁。例如,當我們在維基百科上閱讀文章時,我們的電腦和網頁瀏覽器就被當作一個客戶端,同時,組成維基百科的電腦、資料庫和應用程式被當作伺服器。當我們的網頁瀏覽器向維基百科請求一篇指定的文章時,維基百科伺服器會從維基百科的資料庫中找出該文章的所有資訊,並將這些資訊結合成一個網頁,再發送給我們的瀏覽器。
C/S模式是一個邏輯概念,不是指計算機裝置。在C/S模式中,請求方叫作客戶端,響應請求方叫作伺服器,如果一個伺服器在響應客戶端請求時不能單獨完成任務,則還可能向其他伺服器發出請求,這時,發出請求的伺服器就成為另一個伺服器的客戶端。從雙方建立聯絡的方式來看,主動啟動通訊的應用叫作客戶端,被動等待通訊的應用叫作伺服器。它們的通訊過程如圖4.8所示。
圖4.8
客戶端-伺服器模式主要用於電子郵件、檔案共享和銀行等線上應用程式中。
主從裝置模式
主從裝置(Master-Slave)模式也叫作主僕模式,它基於分而治之的思想,將一個原始任務分解為若干個語義等同的子任務,並由專門的工作者執行緒並行執行這些任務,原始任務的執行結果是透過整合各個子任務的處理結果形成的。主從裝置模式如圖4.9所示。
圖4.9
主從裝置模式的使用場景如下。
◎ 在資料庫的主從設計中,從庫的資料是透過同步主庫的資料而來的。
◎ 計算機系統中主從驅動器的設計原理。
管道-過濾器模式
管道過濾器(Pipe-And-Filter)確定了系統的架構模式,它和工業流水線一樣,原材料在透過流水線上的一道道工序後,形成了某種商業產品。在管道過濾器中,一個個的過濾器會對資料進行過濾,最後得到需要的資料。
管道負責資料的傳遞,它將原始資料傳遞給第1個過濾器,將一個過濾器的輸出傳遞給下一個過濾器,作為下一個過濾器的輸入,重複這個過程,直到處理結束。需要注意的是,管道只是對資料傳輸的抽象,它可能是管道,也可能是其他通訊方式,甚至什麼都沒有(所有過濾器都在原始資料的基礎上進行處理)。
過濾器只負責處理資料,可以有多個,每個過濾器都對原始資料做特定的處理,它們之間沒有任何依賴關係,一個過濾器不必知道其他過濾器的存在。這種松耦合的設計,使得過濾器只需要實現單一的功能來降低了系統的複雜度,也使得過濾器之間的依賴最小,從而以更加靈活的組合來實現新的功能,如圖4.10所示。
圖4.10
管道-過濾器模式的使用場景如下。
◎ 編譯器。
◎ 生物資訊學的工作流。
代理模式
代理模式用於在結構化系統中對元件進行解耦,系統內各元件之間採用遠端呼叫的方式進行互動,代理元件充當元件間通訊的協調角色,提供服務的元件將其能力(服務及特性)釋出給代理,客戶端均向代理請求服務,由代理將請求重定向到先前已釋出過對應服務的元件進行處理,如圖4.11所示。
圖4.11
代理模式多用於訊息代理軟體中,例如ActiveMQ、Kafka、RabbitMQ和JBoss Messaging等。
P2P模式
P2P(Peer-to-Peer,點對點)是一種網路技術,依賴網路中各節點的計算能力和頻寬,而不是把依賴都聚集在有限的幾臺伺服器上。
P2P架構的核心思想是每個節點既是客戶端(Client),又是伺服器端(Server),如圖4.12所示。
圖4.12
P2P(Point to Point,點對點)是下載術語,指我們的電腦在下載的同時要繼續做主機上傳。在這種下載方式中,參與下載的電腦越多,下載速度越快,但是對硬碟損傷較大(在寫的同時還要讀),對記憶體佔用也較多,影響整機速度。
P2P在網路隱私要求高和檔案共享的領域得到了廣泛應用,使用純P2P技術的網路系統有比特幣等。另外,P2P 技術也被用於類似 VoIP等實時媒體業務的資料通訊中。有些網路涉及搜尋的一些功能,也使用客戶端-伺服器結構,但使用 P2P 結構來實現另外一些功能,這種網路設計模型不同於客戶端-伺服器模型,在客戶端-伺服器模型中通訊通常來往於一臺中央伺服器。
P2P網路主要用於讓所有客戶端都能提供資源,比如頻寬、儲存空間和計算能力。當有節點加入且對系統請求增多時,整個系統的容量也增加,這是具有一組固定伺服器的客戶端-伺服器結構不能實現的,因為在這種結構中,客戶端的增加意味著所有使用者更慢速度的資料傳輸。P2P網路的分佈特性透過在多節點上覆制資料展現,這也增加了防故障的健壯性,並且在純P2P網路中,節點不需要依靠一箇中心索引伺服器來發現資料,系統也不會出現單點崩潰的情況。
P2P模式的使用場景如下。
◎ 像Gnutella和G2這樣的檔案共享網路。
◎ 多媒體協議如P2PTV和PDTP。
◎ 像Spotify這樣的專有多媒體應用程式。
事件匯流排模式
事件匯流排模式如圖4.13所示。這種模式主要處理事件,包括4個主要元件:事件源、事件監聽器、通道和事件匯流排。事件源將訊息釋出到事件匯流排的特定通道上;事件監聽器訂閱特定的通道,它會被通知訊息,這些訊息被髮布到它們之前訂閱的一個通道上。
圖4.13
事件匯流排模式的使用場景如下。
◎ 安卓開發。
◎ 通知服務。
MVC模式
MVC(Model View Controller,模型-檢視-控制器)的概念存在很長時間了,但是隨著網際網路的發展,對客戶端-伺服器應用的需求日益增加,它才作為最佳設計方式被更多的人熟知。所有 Web框架都基於 MVC概念構建而成。MVC設計模式的概念也非常容易理解。
◎ 模型(M)是資料的表述,它不是真正的資料,而是資料的介面。我們在使用模型從資料庫中獲取資料時,無須知道底層資料庫錯綜複雜的知識。模型通常還會為資料庫提供一層抽象,這樣同一模型就能使用不同的資料庫。
◎ 檢視(V)是我們看到的介面,它是模型的表現層。在電腦中,檢視是我們在瀏覽器中看到的We b應用的頁面,或者桌面應用的UI。檢視還提供了收集使用者輸入的介面。
◎ 控制器(C)控制模型和檢視之間的資訊流動。它透過程式邏輯來判斷模型從資料庫中獲取了什麼資訊,以及將什麼資訊傳給了檢視。它還透過檢視從使用者那裡收集資訊,並且實現業務邏輯、變更檢視,或者透過模型修改資料,抑或二者兼具。MVC模式如圖4.14所示。
圖4.14
MVC模式的使用場景如下。
◎ 網際網路應用程式的體系架構。
◎ 像Django和Rails這樣的Web框架。
黑板模式
黑板模式是一種常用的架構模式,是對觀察者模式的擴充套件,由3個主要部分組成,如圖4.15所示。
圖4.15
◎ 知識源:包含與應用程式相關的獨立資訊,資訊源之間不直接進行通訊,它們之間的互動只通過黑板完成。
◎ 黑板資料:黑板資料指按照與應用程式相關的層次來組織並解決問題的資料,知識源透過不斷地改變黑板資料來解決問題。
◎ 控制:完全由黑板的狀態驅動,黑板狀態的改變決定了我們需要使用的特定知識。
所有元件都可以訪問黑板。元件可以生成新增到黑板上的新資料物件,它在黑板上查詢特定型別的資料,並透過與現有知識源的模式匹配來查詢這些資料。
黑板模式的使用場景如下。
◎ 語音識別。
◎ 車輛識別和跟蹤。
◎ 蛋白質結構識別。
◎ 對聲吶訊號的解釋。
直譯器模式
直譯器模式屬於行為型模式,實現了一個表示式介面,該介面解釋一個特定的上下文,常用於符號處理引擎、SQL解析等中。直譯器模式如圖4.16所示。
圖4.16
下面對如圖4.16所示的名詞進行解釋。
◎ 抽象表示式角色(Expression):宣告所有的具體表達式角色都需要實現的一個抽象介面。這個介面主要是一個interpret()方法,叫作解釋操作。
◎ 終結符表示式角色(Terminal Expression):實現了抽象表示式角色所要求的介面,主要是一個interpret()方法;文法中的每一個終結符都有一個具體的終結表示式與之對應。比如有一個簡單的公式R=R1+R2,其中的R1和R2就是終結符,對應的解析R1和R2的直譯器就是終結符表示式。◎ 非終結表示式角色(Nonterminal Expression):文法中的每一條規則都需要一個具體的非終結符表示式,非終結符表示式一般是文法中的運算子或者其他關鍵字,比如在公式R=R1+R2中,“+”就是非終結符,解析“+”的直譯器就是一個非終結符表示式。
◎ 環境角色(Context):這個角色的任務一般是存放文法中各個終結符所對應的具體值,比如R=R1+R2,我們給R1賦值100,給R2賦值200,這些資訊都需要被存放到環境角色中,在很多情況下我們使用Map來充當環境角色就夠了。
直譯器模式的使用場景如下。
◎ 資料庫查詢語言,比如SQL。
◎ 用於描述通訊協議的語言。