DDD 落地的思考 --MVC-DDD 理論與實踐

一、背景

之前與一位羣友討論如何在 MVC 應用架構下使用 DDD,讓 DDD 的一些戰略戰術模式配合 MVC 的一些架構元素來完成整個應用工程的重構升級,本篇文章將重點剖析 MVC 架構的一些核心特徵,同時讓 DDD 的經典分層架構與之融合,實現 "上帝的歸上帝, 凱撒的歸凱撒"。

二、MVC 架構梳理

2.1 MVC 架構圖

SpringMVC 架構視圖. png

2.2 MVC 架構元素剖析

  1. 模型 (Model)

從上面的架構圖可以知道模型其實包含了兩個職責,一個是代表業務模型在頁面表示的數據容器,比如 BookVO 或者 Book 對象,另外一個則是與視圖功能相關的業務功能,比如到控制器及其底層的 service 層都可能使用這個模型。從隱含意義上來講,模型可能還會與特定的視圖進行綁定。

  1. 視圖 (View)

在後端的視角下視圖就是頁面,或者彈框,所以視圖會藉助前端的渲染和數據綁定技術來解釋模型。另外一方面視圖將頁面跳轉路由控制的功能由後端驅動。

  1. 控制器 (Controller)

通過上面的分析其實不難發現,控制器是整個架構的核心元素,控制器一方面控制返回模型數據一方面控制視圖路由,這就造成了控制器的職責不再單一,同時也顯著的耦合了視圖的架構元素。

2.3 MVC 架構的層次調用關係梳理

現在我們看一下 MVC 架構的層次調用關係,假設是一個 xxx 管理系統,那這裏的調用鏈路就是 用戶 --->選擇視圖 ---->後端返回視圖 ---->用戶輸入數據 (視圖)-----> 控制器校驗數據 --->控制器調用 service 處理業務 --->service 調用數據庫存儲視圖。從調用層次關係上來看 MVC 架構的一個本質特徵是更面向用戶接口層和應用層的架構,同時實現了前端的視圖路由控制功能。

三、MVC 架構整合 DDD

現在我們來看一下 MVC 如何整合 DDD,從上面的分析可以看到 MVC 架構是與前端嚴重耦合的,根據目前的架構演進趨勢前後端分離基本已經是業界的事實標準了,所以在整合之前需要注意一點就是,當前的應用架構是否需要前後端分離,或者是否需要後端控制器來實現頁面視圖的路由。另外就需要對 MVC 架構的每個元素的職責進行重新劃分。

3.1 C 上浮與職責剝離

現在我們看一下如何對控制器進行調整,如果要讓控制器去對接 DDD 的分層架構的話,那麼很明顯的就是控制器就代表着用戶接口層,但是需要注意的是 DDD 中的用戶接口層中沒有涉及太多的技術細節,所以在用戶接口層中不會有很多的 Servlet 或者 Redirect。

目前的 HTTP 框架基本都屏蔽了底層的基本實現了。所以要讓控制器上浮到分層架構的最上面,同時讓 C 儘量也不要代表應用層。現在我們討論一下如果控制器是否承擔路由控制的場景。就目前看如果是的話那妥妥的前後端不分離了,但是依然想進行融合,所以這裏需要在用戶接口層中單獨擴展出一個小模塊來承擔由之前控制器承擔的責任了。 

如果是要進行前後端分離,那對後端是再好不過了,對於控制器而言其職責可以減少到只進行請求和響應。題外話就是如果前後端分離的話,那就是前端來控制頁面路由跳轉和視圖控制了。進而產生的一個效應就是 M 不再與具體的 V 進行綁定,綁定關係由前端自己控制,C 此時已經不太能感知 M 到底要到哪個 V 上了。

3.2 V 拆分隔離

現在我們看一下如果控制器不再參與視圖的路由控制了,那 MVC 架構還成立嗎?個人認爲是成立的,同時對後端來說更輕量化,在前後端協同開發的時候後端其實已經不需要關注 V 的路由控制了,所以 V 需要的功能要從後端隔離出來讓前端實現。熟悉前端的同學都知道,前端框架中的 2 個比較重要的功能特性就是頁面視圖的控制路由還有數據綁定。

以前是通過 JS+JSP 來進行數據綁定和渲染。但是現在看來 JSP 已經沒有人會繼續使用了,所以數據綁定和渲染都需要前端框架來實現。所以這個 V 在改造後的 MVC 架構中已經不再是必須與後端進行綁定了,同時 V 顯得更存粹,比如渲染出的視圖也許根本不需要後端參與數據返回,也就是說 V 已經迴歸到他需要站的位置了。

3.3 M 冗餘下沉

這裏需要特別說明的是網上對 MVC 架構的概念職責描述的都不太一樣,所以不同的博客內容其見解也不一樣,有一種說法會讓 M 看上去像是前端頁面的模型。所以這裏也要去僞存真一下。

現在我們看看如何改造 M 的部分,在 DDD 分層的用戶接口層中的模型就是 DTO,涉及到頁面的也可以是 VO,說白了就是數據容器,所以在寫這一篇之前,先寫了數據容器模式,這樣的話更容易理解。那麼對於 M 來說其下一層是不建議透出到 Service 層了,所以一個必須的操作就是要將 V 複製到領域層,當作領域模型,也就是說需要兩層模型來進行融合,讓 M 只存在於用戶接口層 (也就是控制器層)。當然也不是無腦複製,改個名就完事了,如果當作領域模型的話個人建議還需要按照領域模型的構建規則進行重新梳理。所以上面的工作會產生另外一個模塊,就是模型轉換工具, MapStruct 或者 Spring BeanUtils 都可以。

3.4 拆分後的 MVC+DDD 分層架構視圖

現在我們來看一下拆分後的 MVC 架構 + DDD 分層應用架構的視圖。上面的架構圖中虛線的組件不是必須的或者是可以使用之前 MVC 架構下的模塊,需要說明的是視圖控制器是區別於是否需要前後端分離的一個重要標誌,有可能是前端代碼也在後端工程項目下,但是視圖控制器也不存在了,此時也算前後端分離。由於 SpringMVC 架構的話可能面向頁面的一些操作不是很複雜,所以在項目初期的話可以使用一層轉換,讓領域實體與數據庫實體作爲一個模型,這樣的話會簡單一點。後期改造的話可以慢慢按標準的 DDD 分層架構去重構底層服務。

四、MVC 架構是否過時

MVC 發展的鼎盛時期,其實更關注於前後端的配合,由於前端技術的限制,不能很好的控制頁面跳轉,所以 MVC 架構就是一個前後端不分離的架構,同時就目前看 MVC 架構是比較少見的由後端驅動前端的架構方法。 

從趨勢上看 MVC 架構可能已經過時了,但是對於想走全棧路線或者公司沒有前端資源等情況下 MVC 架構是後端程序員能選的一種合適的方案。當然另外一方面,對於 MVC 架構的實現流程和源碼在面試過程中也會有所體現,如果哪天不問了,或許是真過時了。

五、實戰案例

在天畫的前端低代碼的實現過程中就是深入實踐了 MVC+DDD 的融合架構,項目初期使用了前後端不分離的模式,在用戶接口層單獨構建了視圖控制器模塊,其他則只是請求響應接口。後期參考 Amis 的 web 項目 Demo 做了前後端分離的模式,讓前端代碼單獨用工程來構建,與後端代碼完全剝離。 

最近在工廠 2.0 項目中已經完全採用了 MVC+DDD 架構前後端分離的項目了,藉助成熟的前端框架,相信後端程序員也可以快速構建全棧應用。想要了解項目詳情的同學可以關注下面的項目: 

天畫前端低代碼平臺: https://gitee.com/sky-painting/amis4j

天畫數據工廠平臺: https://gitee.com/sky-painting/data-factory

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/2ACPkKju7zkcTzRFcqcC3Q