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

发布于:2025-07-29 ⋅ 阅读:(14) ⋅ 点赞:(0)

🧠 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;在战术实施中优先保证聚合根的完整性设计加粗样式


网站公告

今日签到

点亮在社区的每一天
去签到