DDD领域驱动设计:验证订单关联活跃客户的最佳实践
订单创建时验证关联客户活跃状态的最佳实践
一、验证规则的核心最佳实践
- 将验证逻辑内聚到领域层:这是核心业务规则,必须归属领域模型范畴,不能散落在应用层或数据库层面。确保任何创建订单的途径都无法绕开该规则,杜绝漏验证的可能。
- 依赖完整客户实体而非仅ID:创建订单时,不要仅传入客户ID就直接生成订单。需先通过仓储获取完整的
Client实体再做状态校验——这样能确保拿到的是最新的客户状态,避免出现“查完ID对应状态后,客户状态被并发修改”的一致性问题。 - 封装客户状态判断逻辑:在
Client实体中封装isActive()方法,把“活跃状态”的判断规则(比如启用标志为true、账号未过期等复合条件)藏在实体内部。订单创建时只需调用该方法,无需关心具体判断细节,符合面向对象封装原则。 - 遵循快速失败原则:在订单创建的最早期阶段执行验证,一旦发现客户不活跃,立刻抛出领域自定义异常(比如
InactiveClientException),避免后续无效流程的资源消耗。
二、验证的最佳调用位置
1. 订单实体的构造函数/工厂方法(最推荐)
直接在订单的创建入口做验证,确保所有订单实例的生成都必须经过规则校验。示例代码(Java):
public class Order { private final Client client; // 其他业务字段 // 私有构造,强制通过工厂方法创建 private Order(Client client, /* 其他参数 */) { if (!client.isActive()) { throw new InactiveClientException("无法为非活跃客户创建订单"); } this.client = client; // 初始化其他字段 } // 公开工厂方法,作为创建订单的唯一入口 public static Order create(Client client, /* 其他参数 */) { return new Order(client, /* 其他参数 */); } }
2. 应用服务层(辅助前置校验)
如果订单创建流程复杂(比如需要先做参数格式校验、获取其他关联数据),应用服务可以在调用订单工厂前,先从仓储获取Client并做初步校验,但最终的业务规则验证必须由领域层执行——应用层仅负责准备合法的Client实体,把业务判断权交还给领域模型。
3. 禁止在基础设施层做验证
仓储(Repository)仅负责数据持久化操作,不能在此处添加业务规则校验,否则会导致业务逻辑分散,后期维护成本陡增。
三、额外注意事项
- 并发场景的一致性保障:若担心“获取客户到创建订单”的间隙中,客户状态被并发修改,可结合数据库事务加行锁,或在订单保存前再次校验客户状态,确保数据一致性。
- 使用领域自定义异常:抛出的异常需为领域特定的自定义异常,而非通用运行时异常,方便上层调用者精准捕获并返回给用户明确的错误提示(比如“该客户账户已停用,无法创建订单”)。
内容的提问来源于stack exchange,提问作者MIKAELM3
相关产品推荐
相关产品推荐

