貧血模型與充血模型:架構設計的分水嶺

在企業級應用的架構設計中,貧血模型和充血模型一直是架構師們爭論的熱點話題。兩者背后分別代表著“事務腳本模式”和“領域模型模式”兩種截然不同的設計思想。而理解這兩者的差異,有助于開發者根據實際業務場景做出更合理的架構決策。

貧血模型:事務腳本模式的延續

貧血模型(Anemic Domain Model)最早大規模應用于 EJB2 時代,后由 Spring 發揚光大。其核心思想是將狀態行為解耦:

  • 狀態:由一組僅包含屬性、getter 和 setter 的對象承載,這類對象通常被稱為 VO(Value Object)。
  • 行為:由一組服務類(如 Service、Manager、Logic)來承載,負責執行所有的業務邏輯。

這種模式本質上延續了面向過程編程的思想。正如 Spring 創始人 Rod Johnson 所言,Spring 在某種程度上只是 EJB2 事務腳本模式的現代延續。

看似合理,實則反模式

乍一看,貧血模型在命名上貼近業務領域,各種對象之間結構清晰,看似具備良好的領域建模能力。但深入觀察便會發現,這些“領域對象”大多是空殼,缺乏任何實際行為,僅僅是一堆字段加上 getter/setter 方法。

業務邏輯被統一放入 Service 層中,使得原本面向對象的架構逐漸滑向面向過程。這不僅違背了面向對象設計“將狀態與行為綁定”的核心原則,也導致了如下問題:

  • 設計成本與收益不匹配:雖然引入了領域模型的架構和成本(如 ORM 映射),但卻沒有享受到領域建模帶來的好處。
  • 失去封裝優勢:邏輯分散在大量服務方法中,難以復用和擴展。
  • 邏輯難以歸屬:領域邏輯到底屬于哪個 Service,往往眾說紛紜,導致職責混亂。

Martin Fowler 曾在《企業應用架構模式》中指出,領域模型并不總是最合適的選擇。但如果選擇了它,就必須充分利用其優勢——將業務邏輯封裝在模型之中。

這不是分層設計的對立面

有人誤以為,把行為寫進領域對象,就破壞了分層架構。其實不然。只要對象中承載的是與該對象語義強相關的行為(如驗證、計算、規則),就屬于領域邏輯,是完全可以也應該放在模型內部的。而像數據源操作、UI邏輯等當然應該放在其他層處理。

Evans 是怎么說的?

在《領域驅動設計》一書中,Eric Evans 對不同層次的職責做了清晰的劃分:

  • 應用層(Service):協調任務、調度模型、提供任務狀態,不包含業務規則。
  • 領域層(Model):承載全部業務知識,操作業務狀態,是系統的核心。

他強調,Service 層應該很薄,所有重要邏輯都應由模型來執行。可惜,很多人沒有深入理解這一思想,導致架構異化為純 Service 操作模型數據的腳本系統。

為什么貧血模型廣泛存在?

很大程度上,是因為:

  • 許多開發者從未見識過優秀的領域建模實例。
  • 傳統的 CRUD 思維、數據導向開發方式深入人心。
  • 技術歷史遺留(如 EJB)讓人習慣于數據和邏輯分離。

但代價是巨大的。一個項目若把所有行為塞進 Service 層,不僅邏輯難以維護,甚至會徹底喪失面向對象設計的優勢。

貧血模型的優點

不可否認,貧血模型也有其存在的合理性:

  • 簡單直觀:對于業務邏輯極其簡單的系統,使用貧血模型可以快速上手。
  • 易于開發:更貼合數據庫結構,便于初學者理解和操作。

但其缺點也十分明顯:

  • 難以支撐復雜業務:例如某些合同的收入確認規則會因簽署時間、地區等條件而變化,這類規則用 if/else 寫在 Service 中將變得臃腫不堪。
  • 邏輯難以復用與測試:行為分散、模型空洞,導致邏輯難以解耦與單元測試。

充血模型:回歸面向對象的本質

與貧血模型不同,充血模型(Rich Domain Model)強調“對象即行為的載體”。一個對象應當既有狀態(數據),也有行為(邏輯)。

舉個簡單的例子:

傳統貧血設計:

User user = new User();
user.setName("Tom");
userManager.save(user);

充血設計則更符合面向對象原則:

User user = new User("Tom");
user.save();

此時,User 本身擁有保存自己的能力,而不再依賴一個冗余的 UserManager 來操作。

這種設計更具語義性、可讀性和可維護性。它不只是代碼風格的變化,而是設計哲學的轉變。

設計難點:什么邏輯該進模型?

真正難的是界定“哪些邏輯適合放在對象中”。這要求團隊:

  • 理解對象的職責邊界
  • 善于識別業務語義
  • 能夠將復雜規則提煉為清晰的行為

在實踐中,應遵循“高內聚、低耦合”的原則。如果對象內部包含多個子對象,應將相應的職責委托給更細粒度的子對象,從而自然實現責任劃分。這時,策略模式、組合模式等也能更好地發揮作用,取代丑陋的 if/else。

總結

貧血模型與充血模型,代表了面向過程與面向對象的兩種哲學。它們沒有絕對的好壞,關鍵在于是否能根據實際業務需求、團隊能力做出平衡。

  • 簡單業務:貧血模型更容易理解和實現;
  • 復雜系統:充血模型更能保持架構清晰,邏輯內聚。

但如果項目目標是長期演進、高可維護性的企業級系統,充血模型無疑才是面向對象設計的正道


參考資料:

  • 《領域驅動設計》(Eric Evans)
  • Martin Fowler 的博客文章:Anemic Domain Model
  • 知乎相關討論:貧血模型與充血模型的區別與實踐經驗

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/85094.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/85094.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/85094.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux的調試器--gbd/cgbd

1.引入 #include <stdio.h> int Sum(int s, int e) {int result 0;for(int i s; i < e; i){result i;}return result; } int main() {int start 1;int end 100;printf("I will begin\n");int n Sum(start, end);printf("running done, result i…

PPIO × AstrBot:多平臺接入聊天機器人,開啟高效協同 | 教程

在消息平臺接入專屬聊天機器人&#xff0c;能快速生成精準答案&#xff0c;與項目管理、CRM等系統集成后&#xff0c;機器人還能根據任務進展自動建群、推送進度提醒&#xff0c;并精準相關人員&#xff0c;實現信息的高效傳遞。 AstrBot 是一個多平臺聊天機器人及開發框架&…

HAProxy 可觀測性最佳實踐

HAProxy 簡介 HAProxy&#xff08;High Availability Proxy&#xff09;是一款廣泛使用的高性能負載均衡器&#xff0c;支持 TCP 和 HTTP 協議&#xff0c;提供高可用性、負載均衡和代理服務。它特別適用于負載較大的 Web 站點&#xff0c;能夠支持數以萬計的并發連接&#xf…

增強LangChain交互體驗:消息歷史(記憶)功能詳解

背景 在構建聊天機器人時,將對話狀態傳入和傳出鏈至關重要。 LangGraph 實現了內置的持久層,允許鏈狀態自動持久化在內存或外部后端(如 SQLite、Postgres 或 Redis)中。在本文我們將演示如何通過將任意 LangChain runnables 包裝在最小的 LangGraph 應用程序中來添加持久性…

EasyRTC音視頻實時通話助力微信小程序:打造低延遲、高可靠的VoIP端到端呼叫解決方案

一、方案概述? 在數字化通信浪潮下&#xff0c;端到端實時音視頻能力成為剛需。依托龐大用戶生態的微信小程序&#xff0c;是實現此類功能的優質載體。基于WebRTC的EasyRTC音視頻SDK&#xff0c;為小程序VoIP呼叫提供輕量化解決方案&#xff0c;通過技術優化實現低延遲通信&a…

WebVm:無需安裝,一款可以在瀏覽器運行的 Linux 來了

WebVM 是一款可以在瀏覽器中運行的Linux虛擬機。不是那種HTMLJavaScript模擬的UI&#xff0c;完全通過HTML5/WebAssembly技術實現客戶端運行。通過集成CheerpX虛擬化引擎&#xff0c;可直接在瀏覽器中運行未經修改的Debian系統。 Stars 數13054Forks 數2398 主要特點 完整 Lin…

CesiumInstancedMesh 實例

CesiumInstancedMesh 實例 import * as Cesium from cesium;// Three.js 風格的 InstancedMesh 類, https://threejs.org/docs/#api/en/objects/InstancedMesh export class CesiumInstancedMesh {/*** Creates an instance of InstancedMesh.** param {Cesium.Geometry} geom…

創建型模式之Abstract Factory(抽象工廠)

創建型模式之Abstract Factory&#xff08;抽象工廠&#xff09; 摘要&#xff1a; 本文介紹了抽象工廠模式&#xff08;Abstract Factory&#xff09;&#xff0c;它是一種創建型設計模式&#xff0c;提供了一種創建一系列相關對象的接口而無需指定具體類。文章通過手機工廠示…

多卡訓練核心技術詳解

多卡訓練核心技術詳解 多卡訓練 主要圍繞分布式環境初始化、模型并行化、數據分片和梯度同步展開。下面結合您的代碼,詳細解釋這些核心部分: 并行執行命令 torchrun --nproc_per_node=5 TokenLossMulCard.py 1. 分布式環境初始化 def init_distributed():init_process_…

OpenCV---minAreaRect

一、基本概念與用途 minAreaRect是OpenCV中用于計算點集的最小面積旋轉矩形的函數。在計算機視覺領域&#xff0c;它常被用于&#xff1a; 目標檢測中獲取傾斜對象的邊界框&#xff08;如傾斜的車牌、文本行、工業零件&#xff09;形狀分析與識別&#xff08;如確定物體的主方…

高端裝備制造企業如何選擇適配的項目管理系統提升項目執行效率?附選型案例

高端裝備制造項目通常涉及多專業協同、長周期交付和高風險管控&#xff0c;因此系統需具備全生命周期管理能力。例如&#xff0c;北京奧博思公司出品的 PowerProject 項目管理系統就是一款非常適合制造企業使用的項目管理軟件系統。 國內某大型半導體裝備制造企業與奧博思軟件達…

如何科學測量系統的最高QPS?

要準確測量系統的最高QPS&#xff08;Queries Per Second&#xff09;&#xff0c;既不能簡單依賴固定請求數&#xff08;如2萬次&#xff09;&#xff0c;也不能盲目壓到服務器崩潰。以下是專業的方法論和步驟&#xff1a; 1. 核心原則 目標&#xff1a;找到系統在穩定運行&a…

HTML5實現簡潔的端午節節日網站源碼

HTML5實現簡潔的端午節節日網站源碼 前言一、設計來源1.1 網站首頁界面1.2 端午由來界面1.3 節日活動界面1.4 傳統美食界面1.5 民俗文化界面1.6 登錄界面1.7 注冊界面 二、效果和源碼2.1 動態效果2.2 源代碼 結束語 HTML5實現簡潔的端午節節日網站源碼&#xff0c;酷炫的大氣簡…

使用 `\033` 方式設置終端字體顏色

通過 ANSI 轉義序列(以八進制 \033 開頭 ,十進制 27 ),我們可以在支持的終端中輕松實現這一功能。本文將詳細介紹如何使用 \033 設置字體顏色,并提供 C、C++ 和 Python 的示例代碼。 什么是 ANSI 轉義序列? ANSI 轉義序列是一組特殊的字符序列,用于控制終端的顯示屬性…

脫發因素機器學習數據分析

脫發因素機器學習數據分析 一、背景描述 隨著年齡增長&#xff0c;脫發成為影響外貌與健康的重要問題。 本數據集包含遺傳、荷爾蒙變化、醫療狀況、藥物治療、營養缺乏、心理壓力等12個可能導致脫發的因素&#xff0c; 旨在通過數據分析挖掘各因素與脫發的潛在關聯&#xf…

React 第四十八節 Router中 useMatch 的使用詳細介紹及案例分析

前言 useMatch 是 React Router 中的一個鉤子&#xff0c;用于判斷當前 URL 路徑是否與指定模式匹配&#xff0c;并返回匹配的詳細信息。 它常用于動態路由參數提取、條件渲染和導航高亮等場景。 一、useMatch 核心功能 路徑匹配檢測&#xff1a;判斷當前路徑是否符合指定模…

ubuntu mysql 8.0.42 基于二進制日志文件位置和GTID主從復制配置

目錄 1 操作系統信息 2 MySql數據庫版本 3 主機列表 4 MySQL服務器都安裝依賴 5 主庫服務器安裝mysql軟件步驟&#xff1a; 6 從服務器安裝mysql軟件步驟 7 基于二進制日志文件位置的主從復制配置 8 使用全局事務標識符進行主從復制(GTID) 9 部署過程遇到問題 1 操作系…

鴻蒙OSUniApp滑動鎖屏實戰:打造流暢優雅的移動端解鎖體驗#三方框架 #Uniapp

UniApp滑動鎖屏實戰&#xff1a;打造流暢優雅的移動端解鎖體驗 引言 移動應用的安全性和用戶體驗是開發中不可忽視的重要環節。滑動鎖屏作為一種直觀、安全且用戶友好的解鎖方式&#xff0c;在移動應用中得到廣泛應用。本文將深入探討如何使用UniApp框架實現一個功能完備、動…

專場回顧 | 重新定義交互,智能硬件的未來設計

自2022年起&#xff0c;中國智能硬件行業呈現出蓬勃發展的態勢&#xff0c;市場規模不斷擴大。一個多月前&#xff0c;“小智AI”在短視頻平臺的爆火將智能硬件帶向了大眾視野&#xff0c;也意味著智能硬件已不再僅僅停留在概念和技術層面&#xff0c;而是加速邁向實際落地應用…

zynq 級聯多個ssd方案設計(ECAM BUG修改)

本文講解采用zynq7045芯片如何實現200T容量高速存儲方案設計&#xff0c;對于大容量高速存儲卡&#xff0c;首先會想到采用pcie switch級聯方式&#xff0c;因為單張ssd的容量是有限制的&#xff08;目前常見的m.2接口容量為4TB&#xff0c;U.2接口容量為16TB&#xff09;&…