首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

聊一聊贫血模型和充血模型区别

  • 25-04-21 22:00
  • 4088
  • 8623
juejin.cn

在软件设计中,贫血模型(Anemic Domain Model)和充血模型(Rich Domain Model)是两种截然不同的领域模型设计模式,尤其在领域驱动设计(DDD)中它们的区别至关重要。以下是详细解释和对比:


1. 贫血模型(Anemic Domain Model)

定义

  • 数据与行为分离:领域对象(如实体、值对象)仅包含数据属性(Getter/Setter),业务逻辑分散在服务层(Service类)中。
  • 典型特征:
    • 领域对象是“哑巴数据容器”。
    • 业务逻辑集中在Service类中,通过操作领域对象完成功能。
    • 常见于传统分层架构(如Spring MVC + DAO模式)。

代码示例

java
代码解读
复制代码
// 贫血的Order类(仅有数据) public class Order { private String orderId; private List items; private BigDecimal totalAmount; private String status; // Getter/Setter 方法(无业务逻辑) public String getOrderId() { return orderId; } public void setOrderId(String orderId) { this.orderId = orderId; } // ... 其他Getter/Setter } // 业务逻辑集中在Service类 @Service public class OrderService { public void confirmOrder(Order order) { if (order.getItems().isEmpty()) { throw new IllegalStateException("订单不能为空"); } order.setStatus("CONFIRMED"); orderRepository.save(order); } }

缺点

  • 业务逻辑分散:规则散落在多个Service类中,难以维护。
  • 领域对象无意义:对象仅是数据载体,无法表达业务意图。
  • 容易产生重复代码:相同逻辑可能在多个Service中重复实现。
  • 违背面向对象设计:对象失去封装性,成为“数据表映射工具”。

2. 充血模型(Rich Domain Model)

定义

  • 数据与行为统一:领域对象既包含数据属性,也封装业务逻辑。
  • 核心原则:
    • 高内聚:对象的行为与数据紧密关联。
    • 低耦合:通过方法暴露操作,隐藏内部实现细节。
    • 符合面向对象设计:对象是“智能的”,能自主完成职责。

代码示例

java
代码解读
复制代码
// 充血的Order类(数据 + 行为) public class Order { private String orderId; private List items; private Money totalAmount; private OrderStatus status; // 业务逻辑内聚到聚合根 public void addItem(OrderItem item) { if (status != OrderStatus.DRAFT) { throw new IllegalStateException("已确认的订单不可修改"); } items.add(item); totalAmount = totalAmount.add(item.calculateTotal()); } public void confirm() { if (items.isEmpty()) { throw new IllegalStateException("订单不能为空"); } this.status = OrderStatus.CONFIRMED; } // Getter方法(无Setter,通过方法控制状态变更) public String getOrderId() { return orderId; } public List getItems() { return Collections.unmodifiableList(items); } } // 应用服务仅协调流程 @Service public class OrderApplicationService { public void confirmOrder(String orderId) { Order order = orderRepository.findById(orderId); order.confirm(); // 业务逻辑在领域对象中 orderRepository.save(order); } }

优点

  • 业务逻辑集中:规则内聚在领域对象中,易于理解和维护。
  • 表达业务语义:代码直接反映业务概念(如order.confirm())。
  • 减少重复代码:相同逻辑无需在多个Service中重复。
  • 符合DDD原则:支持限界上下文、聚合等模式。

3. 贫血模型 vs. 充血模型

维度贫血模型充血模型
业务逻辑位置分散在Service类中内聚在领域对象中
对象职责数据容器数据 + 行为
代码可维护性低(逻辑分散)高(逻辑集中)
面向对象设计违背封装性符合封装性
典型应用场景简单CRUD系统复杂业务系统(如电商、金融)

4. 如何避免贫血模型?

设计原则

  1. Tell, Don't Ask
    对象应主动执行操作,而非被外部查询状态后修改。

    java
    代码解读
    复制代码
    // ❌ 贫血模型:Service查询状态并修改 if (order.getStatus().equals("DRAFT")) { order.setStatus("CONFIRMED"); } // ✅ 充血模型:对象自己控制状态变更 order.confirm();
  2. 封装不变条件
    将业务规则内聚到对象方法中,例如:

    java
    代码解读
    复制代码
    public class BankAccount { private BigDecimal balance; public void withdraw(BigDecimal amount) { if (balance.compareTo(amount) < 0) { throw new InsufficientBalanceException(); } this.balance = balance.subtract(amount); } }
  3. 减少公开Setter
    通过方法暴露操作,而非直接修改字段:

    java
    代码解读
    复制代码
    // ❌ 允许外部随意修改状态 order.setStatus("CONFIRMED"); // ✅ 仅通过业务方法变更状态 order.confirm();

5. 充血模型的实践挑战

  • 框架适配:JPA/Hibernate等ORM工具可能要求公开Setter或默认构造函数,可通过以下方式解决:

    • 使用protected修饰符限制访问。
    • 通过DTO与领域对象转换(如MapStruct)。
    java
    代码解读
    复制代码
    @Entity public class OrderJpaEntity { // JPA要求字段可访问,但领域对象仍可封装逻辑 private String status; // 转换方法:将JPA实体转换为领域对象 public Order toDomain() { Order order = new Order(id); // 通过领域对象的方法恢复状态 if ("CONFIRMED".equals(status)) { order.confirm(); } return order; } }
  • 性能优化:避免因过度封装导致性能问题(如频繁加载关联对象),可通过延迟加载或CQRS解决。


总结

  • 贫血模型是反模式,将数据与行为分离,导致代码臃肿和维护困难。
  • 充血模型是DDD的核心实践,通过内聚业务逻辑到领域对象中,提升代码表达力和可维护性。
  • 关键设计原则:封装业务规则、减少公开Setter、通过方法暴露操作。
注:本文转载自juejin.cn的雷渊的文章"https://juejin.cn/post/7495570300122873868"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2491) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

103
后端
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top