🧠 DDD领域驱动中瘦模型与富态模型的核心区别
引用:
最肯忘卻古人詩
最不屑一顧是相思
春又來看紅豆開
竟不見有情人去采
🧬 1. 核心定义与哲学思想
🏁 瘦模型(Anemic Model)
【定义】 只包含数据字段和基础getter/setter方法的"哑对象",业务逻辑外置于服务层 。
【哲学】 源自面向过程思想,强调"数据与行为分离 ",类似于C语言结构体。
C++结构示例 📐:
cpp
// 纯数据载体
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++实现 📐:
cpp
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. 应用场景深度分析
💡 瘦模型适用场景
- 简单CRUD系统:如后台管理系统,业务规则少
- 需极简架构场景:微服务间数据传输(DTO模式)
- 重度依赖框架的遗留系统:如使用Hibernate且需脱离数据库逻辑
- 高性能要求场景:避免对象方法调用开销
💡 富态模型适用场景
- 复杂业务核心域:如电商交易系统、风控引擎
- 领域逻辑频繁变更:封装变化点降低维护成本
- 需强一致性保证:如银行账户扣款+流水记录原子操作
- 业务规则易用性优先:降低Service层复杂度
⚖️ 4. 优劣势深度剖析
🛡️ 富态模型核心优势
优势 | 原理说明 | DDD设计影响 |
---|---|---|
领域自洽性 | 💎 对象自含完整性校验逻辑(如 deductBalance() ) |
实现聚合根的自治性 |
高可维护性 | 🔧 业务变更仅需修改领域对象 | 契合限界上下文(Bounded Context) |
表达领域语言 | 🗣️ 方法名如 placeOrder() 直接映射领域事件 |
强化统一语言(Ubiquitous Language) |
防贫血设计 | 🩸 根治Martin Fowler提出的贫血模型问题 | 符合DDD战术设计原则 |
并发控制优化 | 🔒 聚合根内提供乐观锁实现点 | 简化事务边界管理 |
⚠️ 富态模型潜在局限
- 对象膨胀风险 ➜ 方法过多时破坏单一职责原则
- 框架适配困难 ➜ ORM框架需支持复杂领域逻辑
- 学习曲线陡峭 ➜ 需深入理解DDD和OOP设计思想
- 性能开销 ➜ 领域对象内聚导致单次操作耗时增加
🧩 5. 实践案例:电商订单系统的对比
🛒 订单处理逻辑实现对比
瘦模型实现(业务逻辑外置):
cpp
// 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); // 状态变更分散
}
富态模型实现(业务逻辑内聚):
cpp
// 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();
}
}
🚦 关键差异点说明
- 状态变更 :富态模型中
status_
由内部状态机控制 - 业务规则 :总价计算封装在
calculateTotal()
私有方法 - 事务边界 :聚合根
OrderRich
保证订单操作原子性 - 领域协作 :直接调用
ItemList
子实体的业务方法
🧭 6. 混合应用策略建议
- 分层架构平衡 ⚖️
简单操作 UI层 应用层 领域层-Rich Model 基础设施层 基础服务层-Anemic - 场景化选择原则 ✅
- 核心域 ➜ 100%富态模型
- 支撑子域 ➜ 瘦模型加速开发
- 通用子域 ➜ 混合设计
- 技术适配方案 🧰
- ORM框架使用EF Core或Hibernate支持聚合根
- 复杂逻辑采用领域服务补充
🧪 7. 富态模型设计进阶技巧
- 状态模式应用:
cpp
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>());
}
};
- 领域事件驱动:
cpp
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;在战术实施中优先保证聚合根的完整性设计 加粗样式