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

DDD领域驱动中瘦模型与富态模型的核心区别

🧠 DDD领域驱动中瘦模型与富态模型的核心区别

引用

  1. 最肯忘卻古人詩 最不屑一顧是相思
  2. 春又來看紅豆開 竟不見有情人去采

🧬 1. 核心定义与哲学思想

🏁 瘦模型(Anemic Model)

【定义】 只包含数据字段和基础getter/setter方法的“哑对象”,业务逻辑外置于服务层
【哲学】 源自面向过程思想,强调“数据与行为分离”,类似于C语言结构体。
C++结构示例 📐:

// 纯数据载体
class CustomerAnemic {
public:std::string name() const { return name_; }void setName(const std::string& name) { name_ = name; }double balance() const { return balance_; }void setBalance(double balance) { balance_ = balance; } private:std::string name_;double balance_ = 0.0;
};// 业务逻辑在服务类中
class CustomerService {
public:void deductBalance(CustomerAnemic& customer, double amount) {if (amount > customer.balance())throw std::runtime_error("Insufficient balance");customer.setBalance(customer.balance() - amount);}
};
🏁 富态模型(Rich Model)

【定义】 数据与行为高度内聚的领域对象,封装业务规则和状态变更逻辑。
【哲学】 遵循面向对象设计原则,核心是“高内聚、低耦合”和“封装不变性”。
C++实现 📐:

class CustomerRich {
public:CustomerRich(const std::string& name, double balance) : name_(name), balance_(balance) {}void deductBalance(double amount) {if (amount > balance_) throw std::runtime_error("Insufficient balance");balance_ -= amount;addTransaction("DEDUCT", amount); // 内部状态联动}void addTransaction(const std::string& type, double amount) {transactions_.push_back({type, amount});}private:std::string name_;double balance_;std::vector<std::pair<std::string, double>> transactions_;
};

🔍 2. 本质区别可视化对比

维度🪫 瘦模型🔋 富态模型
业务逻辑位置❗ 位于Service层✅ 封装在领域对象内部
领域对象角色📦 数据容器(类似DTO)⚙️ 自治的行为主体
状态变更控制⚠️ 外部服务类直接修改状态✅ 仅通过对象方法内部修改
业务规则表达力📉 规则散布在服务类中📈 通过对象方法自然展现领域规则
与DDD的契合度❌ 违反DDD聚合根设计原则✅ 完美实现DDD聚合根概念
数据一致性边界🔓 跨对象逻辑需事务管理🔒 聚合根内天然一致性保证
⭐ 关键区别示意图

在这里插入图片描述


🎯 3. 应用场景深度分析

💡 瘦模型适用场景
  1. 简单CRUD系统:如后台管理系统,业务规则少
  2. 需极简架构场景:微服务间数据传输(DTO模式)
  3. 重度依赖框架的遗留系统:如使用Hibernate且需脱离数据库逻辑
  4. 高性能要求场景:避免对象方法调用开销
💡 富态模型适用场景
  1. 复杂业务核心域:如电商交易系统、风控引擎
  2. 领域逻辑频繁变更:封装变化点降低维护成本
  3. 需强一致性保证:如银行账户扣款+流水记录原子操作
  4. 业务规则易用性优先:降低Service层复杂度

⚖️ 4. 优劣势深度剖析

🛡️ 富态模型核心优势
优势原理说明DDD设计影响
领域自洽性💎 对象自含完整性校验逻辑(如 deductBalance()实现聚合根的自治性
高可维护性🔧 业务变更仅需修改领域对象契合限界上下文(Bounded Context)
表达领域语言🗣️ 方法名如 placeOrder() 直接映射领域事件强化统一语言(Ubiquitous Language)
防贫血设计🩸 根治Martin Fowler提出的贫血模型问题符合DDD战术设计原则
并发控制优化🔒 聚合根内提供乐观锁实现点简化事务边界管理
⚠️ 富态模型潜在局限
  1. 对象膨胀风险 ➜ 方法过多时破坏单一职责原则
  2. 框架适配困难 ➜ ORM框架需支持复杂领域逻辑
  3. 学习曲线陡峭 ➜ 需深入理解DDD和OOP设计思想
  4. 性能开销 ➜ 领域对象内聚导致单次操作耗时增加

🧩 5. 实践案例:电商订单系统的对比

🛒 订单处理逻辑实现对比

瘦模型实现(业务逻辑外置):

// OrderService.cpp
void OrderService::placeOrder(OrderAnemic& order) {if (order.items().empty()) throw InvalidOrder();double total = 0;for (auto& item : order.items()) {total += item.price() * item.quantity();}order.setTotal(total);  // 外部修改状态if (!PaymentService::pay(order.user(), total)) throw PaymentFailed();InventoryService::deductItems(order.items()); // 跨服务调用order.setStatus(PLACED); // 状态变更分散
}

富态模型实现(业务逻辑内聚):

// OrderRich.cpp
void OrderRich::placeOrder() {if (items_.empty()) throw InvalidOrder();total_ = calculateTotal(); // 内部方法处理status_.attemptTransition(PLACING); // 状态机模式auto payment = std::make_shared<Payment>(user_, total_);payment->execute();  // 领域事件驱动if (payment->isSuccess()) {items_.deductInventory(); // 领域内聚合协作status_.setStatus(PLACED);} else {status_.setStatus(FAILED);throw PaymentFailed();}
}
🚦 关键差异点说明
  1. 状态变更:富态模型中status_由内部状态机控制
  2. 业务规则:总价计算封装在calculateTotal()私有方法
  3. 事务边界:聚合根OrderRich保证订单操作原子性
  4. 领域协作:直接调用ItemList子实体的业务方法

🧭 6. 混合应用策略建议

  1. 分层架构平衡 ⚖️
    简单操作
    UI层
    应用层
    领域层-Rich Model
    基础设施层
    基础服务层-Anemic
  2. 场景化选择原则
    • 核心域 ➜ 100%富态模型
    • 支撑子域 ➜ 瘦模型加速开发
    • 通用子域 ➜ 混合设计
  3. 技术适配方案 🧰
    • ORM框架使用EF Core或Hibernate支持聚合根
    • 复杂逻辑采用领域服务补充

🧪 7. 富态模型设计进阶技巧

  1. 状态模式应用
class OrderStatus {
public:virtual void ship(OrderRich& order) = 0;// 其他状态方法...
};class PlacedStatus : public OrderStatus {
public:void ship(OrderRich& order) override {order.notifyShipped();order.setStatus(std::make_unique<ShippedStatus>());}
};
  1. 领域事件驱动
class OrderRich {
public:void addDomainEvent(std::unique_ptr<DomainEvent> event) {domainEvents_.push_back(std::move(event));}void publishEvents() {for (auto& event : domainEvents_) DomainEventPublisher::publish(*event);domainEvents_.clear();}
private:std::vector<std::unique_ptr<DomainEvent>> domainEvents_;
};

🔚 8. 结论

瘦模型作为简单的数据传输结构,在非核心领域可提供快速实现方案。而富态模型作为DDD的战术核心,通过内聚领域逻辑,在构建复杂业务系统时提供:
✅ 更清晰的业务语义表达
✅ 更强的模型一致性保证
✅ 更高的内聚度和可维护性


💎 决策矩阵
在这里插入图片描述

建议:在战略层面识别核心域,富态模型投入产出比可达10:1;在战术实施中优先保证聚合根的完整性设计加粗样式

http://www.xdnf.cn/news/16608.html

相关文章:

  • SpringCloude快速入门
  • 2025最新Mybatis-plus教程(三)
  • java的break能加标签,return可以加标签吗
  • Java#包管理器来时的路
  • 常见认证机制详解
  • Python爬虫入门:从零开始抓取网页数据
  • LeetCode|Day27|70. 爬楼梯|Python刷题笔记
  • print(“\033[31m红\033[32m绿\033[34m蓝\033[0m默认色“)
  • Java学习-------外观模式
  • [spring6: Mvc-异步请求]-源码分析
  • LINUX727 磁盘管理回顾1;配置文件回顾
  • 机械学习初识--什么是机械学习--机械学习有什么重要算法
  • 习题综合练习
  • 数据结构基础内容(第二篇:线性结构)
  • Qt 分裂布局:QSplitter 使用指南
  • 07.4-使用 use 关键字引入路径
  • python中的容器与自定义容器
  • SpringBoot多容器化实例实战
  • FFmpeg——参数详解
  • 墨者:通过手工解决SQL手工注入漏洞测试(MongoDB数据库)
  • C++学习(线程相关)
  • 负载均衡Haproxy
  • SABR-Net
  • uniapp input 聚焦时键盘弹起滚动到对应的部分
  • iOS安全和逆向系列教程 第21篇:iOS应用加密与混淆技术深度剖析
  • Java面试宝典:MySQL性能优化
  • 用 ESP32 和 LCD 轻松显示植物湿度
  • 第十八章:AI的“通感”:揭秘图、文、音的共同语言——CLIP模型
  • 系统整理Python的循环语句和常用方法
  • Keil MDK 嵌入式开发问题:Error: L6218E: Undefined symbol HAL_TIM_PWM_ConfigChannel