领域驱动设计(DDD)【4】之领域建模理论认识

一 领域建模

  • 领域建模(Domain Modeling)是领域驱动设计(DDD, Domain-Driven Design)中的核心实践,它是通过建立模型来反映业务领域知识的过程。简单来说,就是把你业务中最重要、最核心的部分用代码和图表清晰地表达出来。
  • 为什么需要领域建模?
  1. 统一语言:让业务人员和技术人员说"同一种语言"
  2. 清晰边界:明确系统应该做什么,不应该做什么
  3. 指导实现:为后续的代码实现提供清晰蓝图

二 领域建模的核心概念

2.1 实体(Entity)

  • 定义:具有唯一标识的对象,其身份标识在整个生命周期中保持不变,即使属性发生变化。
  • 特点:通过ID而非属性来区分、具有生命周期、可变(属性可以改变)
  • 案例
// 电商系统中的用户实体
public class User {
    private Long id;  // 唯一标识
    private String name;
    private String email;
    
    // 行为方法
    public void changeEmail(String newEmail) {
        this.email = newEmail;
    }
}

2.2 值对象(Value Object)

  • 定义:没有唯一标识的对象,通过属性值来区分。
    特点:不可变(创建后属性不能改变)、无生命周期、通过属性值而非ID来比较
  • 案例
// 地址值对象
public class Address {
    private final String province;
    private final String city;
    private final String detail;
    
    public Address(String province, String city, String detail) {
        this.province = province;
        this.city = city;
        this.detail = detail;
    }
    
    // 无setter方法,体现不可变性
}

2.3 聚合根(Aggregate Root)

  • 定义:一组相关对象的集合,作为数据修改的入口点。
  • 特点:外部只能通过聚合根访问内部对象、保证聚合内的一致性、有明确的边界
  • 案例
// 订单聚合,订单是聚合根
public class Order {
    private Long id;
    private List<OrderItem> items;
    private OrderStatus status;
    
    // 添加订单项的方法
    public void addItem(Product product, int quantity) {
        // 业务规则校验
        if (status != OrderStatus.CREATED) {
            throw new IllegalStateException("订单已确认,不能修改");
        }
        
        items.add(new OrderItem(product, quantity));
    }
}

2.4 领域服务(Domain Service)

  • 定义:当某个操作不适合放在实体或值对象中时,使用领域服务来封装领域逻辑。
  • 特点:无状态、表示领域概念、通常操作多个聚合
  • 案例
// 转账领域服务
public class TransferService {
    public void transfer(Account from, Account to, Money amount) {
        // 业务逻辑
        from.debit(amount);
        to.credit(amount);
        
        // 记录交易历史等
    }
}

2.5 仓储(Repository)

  • 定义:提供聚合根的持久化和检索机制。
  • 特点:每个聚合根对应一个仓储、隐藏持久化细节、提供集合式的接口
  • 案例
public interface OrderRepository {
    Order findById(Long id);
    void save(Order order);
    void delete(Order order);
}

三 实体管理关系详解

  • 在DDD中,实体之间的关系需要谨慎处理,以下是常见的几种关系:

3.1 一对一关系

  • 案例:用户和用户详情
public class User {
    private Long id;
    private UserDetail detail; // 一对一
}

public class UserDetail {
    private String realName;
    private String idCard;
}

3.2 一对多关系

  • 案例:订单和订单项
public class Order {
    private Long id;
    private List<OrderItem> items; // 一对多
}

public class OrderItem {
    private Product product;
    private int quantity;
}

3.3 多对多关系

  • 案例:学生和课程
public class Student {
    private Long id;
    private Set<Course> courses; // 多对多
}

public class Course {
    private Long id;
    private Set<Student> students; // 反向多对多
}

3.4 重要原则:

  1. 尽量使用ID引用而非对象引用:减少聚合间的直接耦合

    public class Order {
        private Long customerId; // 使用ID引用客户
        // 而不是 private Customer customer;
    }
    
  2. 避免大聚合:保持聚合小巧,提高性能

  3. 跨聚合修改通过领域事件:保证一致性

四 领域建模实战案例:电商系统

  • 让我们通过一个电商系统的例子来实践领域建模:

4.1 识别核心领域

电商核心领域可能包括:

  • 商品管理
  • 订单处理
  • 支付
  • 物流

4.2 关键聚合设计

  • 商品聚合
// 聚合根
public class Product {
    private Long id; // 商品号
    private String name; //商品名
    private Price price; // 值对象 价格
    private Inventory inventory; // 值对象 库存
    
    public void changePrice(BigDecimal newPrice) {
        this.price = new Price(newPrice);
    }
}
  • 订单聚合
public class Order {
    private Long id;
    private Long customerId;
    private List<OrderItem> items;
    private OrderStatus status;
    
    public void confirm() {
        // 业务规则校验
        if (items.isEmpty()) {
            throw new IllegalStateException("订单不能为空");
        }
        this.status = OrderStatus.CONFIRMED;
    }
}

4.3 领域服务示例

public class OrderService {
    private final OrderRepository orderRepository;
    private final InventoryService inventoryService;
    
    public void placeOrder(Customer customer, List<Product> products) {
        // 检查库存
        if (!inventoryService.checkStock(products)) {
            throw new BusinessException("库存不足");
        }
        
        // 创建订单
        Order order = new Order(customer.getId(), products);
        orderRepository.save(order);
        
        // 扣减库存
        inventoryService.reduceStock(products);
    }
}

五 领域建模的常见误区

  1. 贫血模型:只有getter/setter,没有业务逻辑
    // 反例:贫血模型
    public class Order {
        private Long id;
        private String status;
        // 只有getter/setter,没有业务方法
    }
    
  2. 过度设计:为每个概念都创建类,导致模型过于复杂
  3. 忽略限界上下文:没有明确划分不同业务边界
  4. 持久化驱动设计:让数据库表设计主导领域模型

六 领域建模的最佳实践

  1. 从业务出发:与领域专家密切合作
  2. 小步迭代:模型随着对业务的理解不断演进
  3. 使用统一语言:确保业务和技术术语一致
  4. 保持模型纯净:不混入技术实现细节
  5. 适当使用工具:如事件风暴(Event Storming)帮助建模

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值