贫血模型与充血模型:架构设计的分水岭

在企业级应用的架构设计中,贫血模型和充血模型一直是架构师们争论的热点话题。两者背后分别代表着“事务脚本模式”和“领域模型模式”两种截然不同的设计思想。而理解这两者的差异,有助于开发者根据实际业务场景做出更合理的架构决策。

贫血模型:事务脚本模式的延续

贫血模型(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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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;&…