如何入门面向对象领域模型(DDD),实现变量与业务逻辑的深度绑定?
- 内容介绍
- 相关推荐
本文共计1011个文字,预计阅读时间需要5分钟。
面向对象领域模型不仅仅是将变量填充进类中就完事,关键在于让变量承载业务含义、遵循业务规则约束,并与行为自然融合。DDD的深度绑定本质上是让数据和逻辑在语义上不可分割——比如一个对象不仅包含字段,还通过()、()等方法主动校验是否允许取消、是否已发货、退货是否触发等状态流转规则,将状态流转逻辑内化为对象能力。
变量必须是业务概念,不是技术容器
避免用 String address 这类泛型字段。DDD 要求建模为 Address 值对象,封装省市区、邮编格式校验、标准化输出等逻辑。它没有 ID,不可变,复用时直接传递整个对象。同理,金额不能是 BigDecimal amount,而应是 Money 类,自带货币类型、精度控制、加减运算合法性检查。
- 识别业务中反复出现的“描述性片段”,如地址、时间范围、价格、规格参数——它们大概率是值对象
- 值对象不依赖数据库主键,也不需要单独持久化;它属于某个实体或聚合,随其生命周期存在
- 一旦发现同一组字段在多处重复校验(如手机号格式、邮箱正则),就该抽成值对象
业务逻辑必须落在聚合根内部
聚合是业务一致性的边界。比如订单(Order)作为聚合根,它管理的订单项(OrderItem)、收货地址(Address)、优惠券(Coupon)都只能通过 Order 访问。所有影响订单整体状态的操作——添加商品、应用优惠、确认收货——都必须由 Order 提供方法,且在方法内完成全部校验与状态联动。
- 禁止外部直接修改
order.items.add(...),必须走order.addItem(product, qty) - 取消订单不能只改 status=“CANCELLED”,要同步释放库存、关闭支付单、生成取消记录
- 聚合根方法应返回明确结果(如
Result<Order>或抛出领域异常),不暴露内部集合引用
用领域事件解耦跨聚合的业务响应
当一个操作引发多个聚合变化时(如“订单支付成功”后要扣减库存、通知物流、更新用户积分),不能让 Order 直接调用 InventoryService 或 LogisticsService。正确做法是在 Order 内部发布 OrderPaidEvent,由独立的事件处理器订阅并执行后续动作。
- 领域事件命名用过去时(
OrderCreated、PaymentConfirmed),表示事实已发生 - 事件只携带必要上下文(如 orderId、amount、timestamp),不含业务逻辑
- 事件处理需保证最终一致性,失败可重试或告警,但不影响主流程
统一语言从变量命名开始落地
变量名就是业务术语的代码映射。不用 userStatus,而用 accountStatus(如果领域叫“账户”);不用 deliveryTime,而用 estimatedDeliveryAt(体现预估性);不用 isVIP,而用 membershipTier(支持未来扩展 Gold/Silver/Platinum)。
- 所有类、方法、字段命名必须能被业务人员准确理解并认可
- 遇到歧义词(如“客户”在销售侧指 buyer,在客服侧指 complainant),立即划分限界上下文
- 代码注释不解释“怎么写”,只说明“为什么这么写”——对应哪条业务规则
本文共计1011个文字,预计阅读时间需要5分钟。
面向对象领域模型不仅仅是将变量填充进类中就完事,关键在于让变量承载业务含义、遵循业务规则约束,并与行为自然融合。DDD的深度绑定本质上是让数据和逻辑在语义上不可分割——比如一个对象不仅包含字段,还通过()、()等方法主动校验是否允许取消、是否已发货、退货是否触发等状态流转规则,将状态流转逻辑内化为对象能力。
变量必须是业务概念,不是技术容器
避免用 String address 这类泛型字段。DDD 要求建模为 Address 值对象,封装省市区、邮编格式校验、标准化输出等逻辑。它没有 ID,不可变,复用时直接传递整个对象。同理,金额不能是 BigDecimal amount,而应是 Money 类,自带货币类型、精度控制、加减运算合法性检查。
- 识别业务中反复出现的“描述性片段”,如地址、时间范围、价格、规格参数——它们大概率是值对象
- 值对象不依赖数据库主键,也不需要单独持久化;它属于某个实体或聚合,随其生命周期存在
- 一旦发现同一组字段在多处重复校验(如手机号格式、邮箱正则),就该抽成值对象
业务逻辑必须落在聚合根内部
聚合是业务一致性的边界。比如订单(Order)作为聚合根,它管理的订单项(OrderItem)、收货地址(Address)、优惠券(Coupon)都只能通过 Order 访问。所有影响订单整体状态的操作——添加商品、应用优惠、确认收货——都必须由 Order 提供方法,且在方法内完成全部校验与状态联动。
- 禁止外部直接修改
order.items.add(...),必须走order.addItem(product, qty) - 取消订单不能只改 status=“CANCELLED”,要同步释放库存、关闭支付单、生成取消记录
- 聚合根方法应返回明确结果(如
Result<Order>或抛出领域异常),不暴露内部集合引用
用领域事件解耦跨聚合的业务响应
当一个操作引发多个聚合变化时(如“订单支付成功”后要扣减库存、通知物流、更新用户积分),不能让 Order 直接调用 InventoryService 或 LogisticsService。正确做法是在 Order 内部发布 OrderPaidEvent,由独立的事件处理器订阅并执行后续动作。
- 领域事件命名用过去时(
OrderCreated、PaymentConfirmed),表示事实已发生 - 事件只携带必要上下文(如 orderId、amount、timestamp),不含业务逻辑
- 事件处理需保证最终一致性,失败可重试或告警,但不影响主流程
统一语言从变量命名开始落地
变量名就是业务术语的代码映射。不用 userStatus,而用 accountStatus(如果领域叫“账户”);不用 deliveryTime,而用 estimatedDeliveryAt(体现预估性);不用 isVIP,而用 membershipTier(支持未来扩展 Gold/Silver/Platinum)。
- 所有类、方法、字段命名必须能被业务人员准确理解并认可
- 遇到歧义词(如“客户”在销售侧指 buyer,在客服侧指 complainant),立即划分限界上下文
- 代码注释不解释“怎么写”,只说明“为什么这么写”——对应哪条业务规则

