成爲程序員時,我學到了幾種設計模式:單例模式,存儲庫,工廠,構建者,裝飾者等。設計模式爲咱們提供了一個通過驗證的解決方案,以解決現有的和重複出現的問題。我沒有學到的是,相似的機制存在於更高層次上:軟件架構模式。這些是用於整個應用程序或應用程序佈局的模式。它們都有優勢和缺點。它們都解決了具體問題。下面咱們一一分析:程序員
分層模式數據庫
分層模式多是最着名的軟件體系結構模式之一。許多開發人員在不知道名稱的狀況下使用它。咱們的想法是將您的代碼拆分爲「層」,其中每一個層都有必定的責任,併爲更高層提供服務。後端
沒有預約義數量的圖層,但這些圖層是您常常看到的圖層:設計模式
Presentation(展現或UI層)緩存
Application(應用層)微信
Business(業務或管理層)架構
Persistence(持久性或數據訪問層)微服務
Database(數據庫層)佈局
這個想法是,用戶經過執行一些操做(例如點擊一個按鈕)來啓動表示層中的一段代碼。表示層而後調用底層,即應用層。而後咱們進入業務層,最後,持久層將全部內容存儲在數據庫中。因此更高層依賴於而且調用較低層。性能
根據應用程序的複雜程度,您將看到相應的變體。一些應用程序可能會忽略應用程序層,而其餘應用程序則會添加一個緩存層。甚至能夠將兩個層合併爲一個。例如,ActiveRecord模式結合了業務層和持久層。
每層責任
如前所述,每一層都有本身的責任。表示層包含應用程序的圖形設計,以及處理用戶交互的任何代碼。您不該該在此圖層中添加不特定於用戶界面的邏輯。
業務層是您將模型和邏輯特定於您要解決的業務問題的地方。
應用程序層位於表示層和業務層之間。一方面,它提供了一種抽象,以便表示層不須要知道業務層。理論上,您能夠更改表示層的技術堆棧,而無需更改應用程序中的任何其餘內容(例如,從WinForms更改成WPF)。另外一方面,應用程序層提供了放置不適合業務或表示層的某些協調邏輯的位置。
最後,持久層包含訪問數據庫層的代碼。數據庫層是底層數據庫技術(例如SQL Server,MongoDB)。持久層是操縱數據庫的代碼集合:SQL語句,鏈接細節等。
優勢
大多數開發人員都熟悉這種模式。
它提供了一種編寫組織良好,可測試的應用程序的簡單方法。
缺點
它每每會致使單片應用程序以後很難分開。
開發人員常常發現本身編寫了不少代碼來經過不一樣的圖層,而沒有在這些圖層中添加任何值。若是你所作的只是編寫一個簡單的CRUD應用程序,那麼分層模式可能對你來講太過度了。
適合場景
標準業務線應用程序,不只僅是CRUD(寫讀改刪)操做
微內核
當您的應用程序具備一組核心職責和一組可互換部分時,微內核模式或插件模式很是有用。微內核將提供應用程序的入口點和通常流程,而不知道不一樣的插件正在作什麼。
一個例子是任務調度器。微內核能夠包含用於調度和觸發任務的全部邏輯,而插件包含特定任務。只要插件遵循預約義的API,微內核就能夠觸發它們,而無需瞭解實現細節。
另外一個例子是工做流程。工做流的實現包含諸如不一樣步驟的順序,評估步驟結果,決定下一步是什麼等概念。步驟的具體實現對於工做流的核心代碼來講並不重要。
優勢
這種模式提供了很大的靈活性和可擴展性。
某些實現容許在應用程序運行時添加插件。
微內核和插件能夠由獨立的團隊開發。
缺點
決定什麼屬於微內核,哪些不屬於微內核是很困難的。
預約義的API可能不適合將來的插件。
適合場景
從不一樣來源獲取數據的應用程序,轉換該數據並將其寫入不一樣的目標
工做流應用程序
任務和做業調度應用程序
CQRS
CQRS是命令和查詢責任分離(Command and Query Responsibility Segregation)的首字母縮略詞。這種模式的核心概念是應用程序具備必須徹底分離的讀取操做和寫入操做。這也意味着用於寫操做(命令)的模型將與讀模型(查詢)不一樣。此外,數據將存儲在不一樣的位置。在關係數據庫中,這意味着將有用於命令模型的表格和用於讀取模型的表格。一些實現甚至將不一樣模型存儲在徹底不一樣的數據庫中,例如命令模型的SQL Server和讀取模型的MongoDB。
這種模式一般與事件採購相結合,咱們將在下面介紹。
它是如何工做的?當用戶執行操做時,應用程序會向命令服務發送命令。命令服務從命令數據庫中檢索它須要的全部數據,進行必要的操做並將其存儲回數據庫中。而後它通知讀取服務,以即可以更新讀取模型。這個流程以下所示。
當應用程序須要向用戶顯示數據時,它能夠經過調用讀取服務來檢索讀取的模型,以下所示。
優勢
命令模型能夠專一於業務邏輯和驗證,而讀取模型能夠針對特定場景量身定製。
您能夠避免複雜的查詢(例如,SQL中的鏈接),這使得讀取更加高效。
缺點
保持命令和讀取模型同步可能會變得複雜。
適合場景
指望大量讀取的應用程序
複雜域的應用程序
事件採購
正如我上面提到的,CQRS一般與事件採購密切相關。這是一種模式,它不會將模型的當前狀態存儲在數據庫中,而是存儲模型中發生的事件。所以,當客戶名稱發生變化時,您不會將該值存儲在「名稱」列中。你將存儲一個帶有新值的「NameChanged」事件(也多是舊的)。
當您須要檢索模型時,您將檢索其存儲的全部事件並在新對象上從新應用它們。咱們稱之爲補水對象。
事件採購的現實類比是會計。當您添加費用時,您不會更改總額的值。在會計中,會添加一條新行,並執行操做。若是發生錯誤,只需添加一個新行。爲了讓您的生活更輕鬆,您能夠在每次添加線路時計算總計。這個總數能夠看做是讀取模型。下面的例子應該更清楚。
您能夠看到咱們在添加發票201805時發生了錯誤。咱們添加了兩條新線,而不是更改線:首先,一條線用於取消錯誤線,而後是一條新的正確線。這就是事件採購的工做方式。你永遠不會刪除事件,由於它們在過去不能否認。爲了糾正狀況,咱們添加了新事件。
另外,請注意咱們如何擁有總值的單元格。這只是上面單元格中全部值的總和。在Excel中,它會自動更新,所以您能夠說它與其餘單元格同步。它是閱讀模型,爲用戶提供了一個簡單的視圖。
事件採購一般與CQRS結合使用,由於從新水化對象可能會對性能產生影響,特別是當實例有不少事件時。快速閱讀模式能夠顯着提升應用程序的響應時間。
優勢
該軟件體系結構模式能夠提供開箱即用的審計日誌。每一個事件表示在某個時間點對數據的操縱。
缺點
它須要一些紀律,由於你不能用數據庫中的簡單編輯修正錯誤的數據。
改變事件結構並非一件容易的事情。例如,若是添加屬性,則數據庫仍包含沒有該數據的事件。您的代碼須要慷慨地處理這些缺失的數據。
適合場景
須要將事件發佈到外部系統
將用CQRS構建
須要對數據進行更改的審計日誌
微服務
當您將應用程序編寫爲一組微型服務時,其實是在編寫能夠一塊兒工做的多個應用程序。每一個微服務都有本身獨特的責任,團隊能夠獨立於其餘微服務開發它們。他們之間惟一的依賴是溝通。因爲微服務彼此通訊,所以您必須確保它們之間發送的消息保持向後兼容。這須要一些協調,特別是當不一樣的團隊負責不一樣的微服務時。
一張圖能夠解釋。
在上圖中,應用程序調用一箇中央API,將呼叫轉發到正確的微服務。在本例中,用戶配置文件,庫存,訂單和付款有單獨的服務。你能夠想象這是一個應用程序,用戶能夠訂購一些東西。單獨的微服務也能夠互相調用。例如,支付服務能夠在支付成功時通知訂單服務。訂單服務能夠調用庫存服務來調整庫存。
目前尚未明確規定微服務的規模。在前面的示例中,用戶配置文件服務可能負責數據,如用戶的用戶名和密碼,還包括家庭地址,頭像圖片,收藏夾等。還能夠將全部這些責任分紅更小的一個選項微服務。
優勢
您能夠分別編寫,維護和部署每一個微服務。
微服務架構應該更容易擴展,由於您只能擴展須要擴展的微服務。沒有必要擴展應用程序中不常使用的部分。
重寫應用程序的部分更容易,由於它們更小而且與其餘部分的耦合更少。
缺點
與您所指望的相反,開始編寫結構良好的巨集實際上更容易,稍後將其分解爲微服務。隨着微服務的出現,許多額外的問題開始發揮做用:溝通,協調,向後兼容性,日誌記錄等等。錯過編寫結構良好的巨集的必要技能的團隊可能很難寫出一套很好的微服務。
用戶的單個動做能夠經過多個微服務。還有更多的失敗點,當出現問題時,可能須要更多時間來查明問題。
適合:
應用程序某些部分將被密集使用並須要縮放
爲其餘幾個應用程序提供功能的服務
若是組合成一個總體,那麼應用程序將變得很是複雜
應用程序能夠定義明確的有界上下文
總結
上面列出軟件開發中的幾種軟件架構模式,以及它們的優勢和缺點。可是有比這裏列出的更多的模式。將這些模式中的幾種結合起來也並不罕見。它們並不老是相互排斥的。例如,您能夠擁有多個微服務,其中一些使用分層模式,而其餘使用CQRS和事件源。
須要記住的重要一點是,沒有一種解決方案能夠在任何地方使用。當咱們提出應用程序使用哪一種模式的問題時,古老的答案仍然適用:「這取決於你的項目需求!」。您應該權衡解決方案的優缺點,並作出明智的決定。
本文分享自微信公衆號 - 互聯網後端架構(fullstack888)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。