代碼分層的設計之道

原文地址:梁桂釗的博客前端

博客地址:blog.720ui.com數據庫

歡迎轉載,轉載請註明做者及出處,謝謝!後端

分層思想,是應用系統最多見的一種架構模式,咱們會將系統橫向切割,根據業務職責劃分。MVC 三層架構就是很是典型架構模式,劃分的目的是規劃軟件系統的邏輯結構便於開發維護。MVC:英文即 Model-View-Controller,分紅模型層、視圖層、控制層。將頁面和業務邏輯分離,提升應用的可擴展性及可維護性。如圖所示。緩存

MVC分層結構.png | left | 240x433

事實上,MVC 三層架構只是概念層面的指導思想,咱們會將層次結構劃分的更加細緻。例如,傳統後端的 MVC 模式對於先後端的劃分界限比較模糊。通常狀況下,前端開發人員負責編寫項目的靜態頁面,包括 HTML 頁面、CSS 樣式與 JavaScript 交互部分,並提供給服務端開發人員編寫視圖層業務,甚至有的項目直接讓前端開發人員完成視圖層的業務開發任務。這樣的開發模式形成的問題在於,先後端在開發過程當中分工不明確,而且存在相互強依賴,前端開發人員須要關心服務端的業務,服務端開發人員也須要依賴前端的進度。而且隨着 Android、 IOS、 PC 以及 U3D 等多個客戶端加入,程序的開發成本與維護成本會指數級上升。爲了提升開發效率,細化職責,先後端分離的需求愈來愈被重視。先後端分離在於服務端提供 API 接口,前端調用 AJAX 實現數據交互。如圖所示。微信

MVC三層模型.png | left | 428x314

此外,隨着數據存儲能力的不斷擴展(MySQL、Oracle、Redis、MongoDB、ElasticSearch、PostgreSQL、HBase 等),以及隨着微服務的流行與普及,咱們常常經過 RPC(Dubbo、HSF、Thrift 等)依賴不少外部接口或 HTTP 調用第三方平臺。所以,咱們須要一套細緻劃分的代碼結構。此外,不少時候,咱們在開發過程當中,也並無把它們職責劃分開。例如,在代碼結構中,咱們將很是多的邏輯業務放在了 Controller 層,而只把 Service 做爲數據透傳的途徑了。事實上,這個是不對的。無獨有偶,咱們還會發現有的項目中在 Dao 層調用遠程服務,也有的會在 Service 層或者 Controller 層進行這樣的操做,因爲不一樣研發同窗的習慣不一樣,或者偷工取巧致使開發代碼風格徹底不一樣,代碼層次結構混亂。架構

總結一下,MVC 三層架構只是概念層面的指導思想,咱們會將層次結構劃分的更加細緻。如今,咱們來深刻探討「如何合理的設計代碼分層,論代碼分層的設計之道」。在筆者看來,合理的代碼分層應該是這樣的。如圖所示。框架

代碼分層 (1).jpg | left | 827x699
其中, 數據持久層 承載了數據存儲和訪問的能力,它既與底層數據進行交換,包括 MySQL、Oracle、Redis、MongoDB、ElasticSearch、PostgreSQL、HBase 等,又經過 Pxoxy 的代理和包裝與遠程服務數據進行聯動。所以,在業務邏輯層調用時,它對底層的數據實現方式是無感知的,不管是哪一種數據存儲方式,以及它是遠程數據,仍是本地數據,均可以很是容易的調用。換句話說,咱們須要將數據的查詢和更改操做限制在數據持久層,並只能被業務邏輯層訪問。

那麼,業務邏輯層 的職責是與__數據持久層__交互,對多個數據源的操做進行聚合,而且提供組合複用的能力。此外,它也是業務通用能力的處理層,其中還包括緩存方案、消息監聽(MQ)、定時任務等等。此外,咱們要將盡量多的業務處理放在__業務邏輯層__,包括了參數校驗、數據轉換、異常處理等,而不是在 Controller 再去處理。前後端分離

筆者認爲:請求處理層具備三塊能力,一個是經過模板引擎渲染,例如 FreeMarket、Velocity 的頁面渲染,以及經過 Controller 層封裝的 RESTful API 的 HTTP 接口。若是項目中用到了 Dubbo、HSF、Thrift 等 RPC 服務,咱們還須要提供對於的服務給上游的業務方使用,它經過 Service 來實現並暴露成 RPC 接口。這裏,Service 的命名是相對的,通常經過 Client 提供接口,經過 Service 實現具體的業務邏輯。微服務

咱們瞭解了邏輯結構,那麼,筆者認爲比較清晰的物理代碼結構應該是這樣的。ui

屏幕快照 2018-10-13 下午5.43.16.png | center | 604x1224

那麼,咱們能夠跨層級調用嗎?筆者認爲:咱們須要禁止跨層級調用,由於每一個層級都本身的職責,而且對上層而言是透明的,就像 OSI 七層協議模型和 TCP/IP 四層協議模型同樣,只有將職責限制在本身的邊界內,總體層次結構才清晰明瞭。那麼對於同級調用,筆者認爲在業務邏輯層是容許的,可是,要特別注意循環調用的產生。

如今,咱們再橫向理解幾個領域模型:VO、BO、DO、DTO。這個概念,是由阿里編碼規約提到的,因爲其業務很是複雜,所以爲了更好地進行領域建模和模型隔離,提出了這幾個概念。其中,DO(Data Object)與數據庫表結構一一對應,經過 DAO 層向上傳輸數據源對象。 而 DTO(Data Transfer Object)是遠程調用對象,它是 RPC 服務提供的領域模型。注意的是,對於 DTO 必定要保證其序列化,實現 Serializable 接口,並顯示提供 serialVersionUID,不然在反序列化時,若是 serialVersionUID 被修改,那麼反序列化會失敗。事實上,DO 和 DTO 惟一的區別在於,一個是本地數據源的領域模型,一個是遠程服務的序列化領域模型。對於 BO(Business Object),它是業務邏輯層封裝業務邏輯的對象,通常狀況下,它是聚合了多個數據源的複合對象。那麼,VO(View Object) 一般是請求處理層傳輸的對象,它經過 Spring 框架的轉換後,每每是一個 JSON 對象。例如,你須要解決 Long 類型的數據精度丟失的問題(若是直接傳給 Web 端的話,在 Long 長度大於 17 位時會出現精度丟失),你就能夠在 Controller 層經過 @ResponseBody 將返回數據自動轉換成 JSON 時,統一封裝成字符串。

總結一下,分層思想,將系統橫向切割,根據業務職責劃分。劃分的目的是規劃軟件系統的邏輯結構便於開發維護。可是,隨着微服務的演變和不一樣研發的編碼習慣,每每致使了代碼分層不完全致使引入了「壞味道」。筆者試圖提出一個新的代碼分層思路來規避和規範這種分層結構。

若是你有不一樣的想法和興趣,歡迎加我微信一塊兒探討與交流喲~

(完,轉載請註明做者及出處。)

更多精彩文章,盡在「服務端思惟」!

相關文章
相關標籤/搜索