name: m09-domain description: “关键:用于领域建模。触发词:领域模型,DDD,领域驱动设计,实体,值对象,聚合,仓储模式,业务规则,验证,不变条件,领域模型,领域驱动设计,业务规则” user-invocable: false
领域建模
第2层:设计选择
核心问题
这个概念在领域中的角色是什么?
在代码建模之前,请理解:
- 它是一个实体(身份重要)还是一个值对象(可互换)?
- 必须维护哪些不变条件?
- 聚合边界在哪里?
领域概念 → Rust 模式
| 领域概念 | Rust 模式 | 所有权含义 |
|---|---|---|
| 实体 | struct + Id | 拥有,唯一身份 |
| 值对象 | struct + Clone/Copy | 可共享,不可变 |
| 聚合根 | struct 拥有子项 | 清晰的所有权树 |
| 仓储 | trait | 抽象持久化 |
| 领域事件 | enum | 捕获状态变化 |
| 服务 | impl 块 / 自由函数 | 无状态操作 |
思考提示
在创建领域类型之前:
-
概念的身份是什么?
- 需要唯一身份 → 实体(Id 字段)
- 按值可互换 → 值对象(Clone/Copy)
-
必须保持哪些不变条件?
- 始终有效 → 私有字段 + 已验证的构造函数
- 转换规则 → 类型状态模式
-
谁拥有这些数据?
- 单一所有者(父级) → 拥有的字段
- 共享引用 → Arc/Rc
- 弱引用 → Weak
向上追溯 ↑
到领域约束(第3层):
"我应该如何建模一个交易?"
↑ 问:哪些领域规则管理交易?
↑ 检查:domain-fintech(审计,精度要求)
↑ 检查:业务干系人(哪些不变条件?)
| 设计问题 | 追溯到 | 提问 |
|---|---|---|
| 实体 vs 值对象 | domain-* | 什么使两个实例“相同”? |
| 聚合边界 | domain-* | 什么必须保持一致? |
| 验证规则 | domain-* | 哪些业务规则适用? |
向下追溯 ↓
到实现(第1层):
"建模为实体"
↓ m01-ownership: 拥有,唯一
↓ m05-type-driven: Id 的新类型
"建模为值对象"
↓ m01-ownership: Clone/Copy 可行
↓ m05-type-driven: 在构造时验证
"建模为聚合"
↓ m01-ownership: 父级拥有子级
↓ m02-resource: 考虑在聚合内共享时使用 Rc
快速参考
| DDD 概念 | Rust 模式 | 示例 |
|---|---|---|
| 值对象 | 新类型 | struct Email(String); |
| 实体 | 结构体 + ID | struct User { id: UserId, ... } |
| 聚合 | 模块边界 | mod order { ... } |
| 仓储 | 特征 | trait UserRepo { fn find(...) } |
| 领域事件 | 枚举 | enum OrderEvent { Created, ... } |
模式模板
值对象
struct Email(String);
impl Email {
pub fn new(s: &str) -> Result<Self, ValidationError> {
validate_email(s)?;
Ok(Self(s.to_string()))
}
}
实体
struct UserId(Uuid);
struct User {
id: UserId,
email: Email,
// ... 其他字段
}
impl PartialEq for User {
fn eq(&self, other: &Self) -> bool {
self.id == other.id // 身份相等性
}
}
聚合
mod order {
pub struct Order {
id: OrderId,
items: Vec<OrderItem>, // 拥有的子项
// ...
}
impl Order {
pub fn add_item(&mut self, item: OrderItem) {
// 强制执行聚合不变条件
}
}
}
常见错误
| 错误 | 为什么错 | 更好的做法 |
|---|---|---|
| 原始类型偏执 | 没有类型安全 | 新类型包装器 |
| 带有不变条件的公共字段 | 不变条件被破坏 | 私有 + 访问器 |
| 泄露聚合内部 | 封装被破坏 | 根上的方法 |
| 使用字符串表示语义类型 | 没有验证 | 已验证的新类型 |
相关技能
| 何时 | 参见 |
|---|---|
| 类型驱动的实现 | m05-type-driven |
| 聚合的所有权 | m01-ownership |
| 领域错误处理 | m13-domain-error |
| 特定领域规则 | domain-* |