当前位置: 首页 > news >正文

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

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

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

贫血模型(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
  • 知乎相关讨论:贫血模型与充血模型的区别与实践经验

相关文章:

  • 分库分表内容
  • 智能制造全场景数字化解决方案
  • 跨境电商每周信息差—5.26-5.30
  • 换行符在markdown格式时异常2
  • Ollama(1)知识点配置篇
  • 保险行业数字化应用解决方案
  • DiTAR: Diffusion Transformer Autoregressive Modeling for Speech Generation
  • 网易 - 灵犀办公文档
  • 【术语扫盲】BSP与MSP
  • React 事件处理与合成事件机制揭秘
  • 前端基础之《Vue(17)—路由集成》
  • 正点原子Z20 ZYNQ ​​​开发板​​发布!板载FMC LPC、LVDS LCD和WIFI蓝牙等接口,资料丰富!
  • LangChain表达式(LCEL)实操案例1
  • MathWorks无法注册,显示no healthy upstream(已解决)
  • PyQt6基础_QCharts绘制饼状图
  • 【nn.GroupNorm】
  • MQTT协议,EMQX部署,MQTTX安装学习
  • 苹果签名工具
  • 每天掌握一个Linux命令 - curl
  • 代码随想录算法训练营第60期第五十二天打卡
  • 中国亚马逊网站建设/百度关键词优化软件排名
  • 西安做百度网站公司/关键字排名软件官网
  • b站视频推广网站有哪些/微信软文广告经典案例
  • 时时彩网站怎么做/国外搜索引擎大全
  • 上传文件的网站/搜索引擎优化期末考试答案
  • 怎么做黑客攻击网站/统计网站访问量