04-实体与标识-DDD领域驱动设计


title: "04 实体(Entity)与标识"


学习目标

  • 理解实体(Entity)的定义:以标识(Identity)区分,而不是以属性值区分
  • 能在"实体 vs 值对象(Value Object)"之间做出建模选择,并说清理由
  • 能把"标识、生命周期、相等性(Equality)"这三件事落实到代码与讨论中

核心概念

实体是什么

实体表示领域中的"对象",它的关键特征是:

  • 有稳定的标识(Identity):在其生命周期内保持不变
  • 会随时间变化(Mutable):状态会发生演化(例如订单从 CREATED → PAID)
  • 相等性用标识判断:即使属性值变了,它仍然是"同一个实体"

标识(Identity)是什么

标识是用来回答一句话的:"你是谁?"

在 DDD 中,标识通常不等同于数据库自增主键;它更像领域中的"业务编号/自然键",例如订单号、客户号、合同号等。

在本书示例(订单域)中,Order 的标识是 OrderNumber(值对象),不是 long id

  • OrderNumber:包含格式校验(ORDER-[A-Z0-9]{16}),并被 Order 聚合根持有
  • CustomerId:同样是值对象,用来表达客户的身份

课堂讲授:为什么实体不是"数据库表的一行"

很多初学者会把实体理解为"ORM 的 @Entity"。这会把注意力放到"表结构/字段映射",而忽略实体的真正价值:封装业务规则与状态演化

一个好用的教学判断:

  • 如果你在讨论中频繁使用"同一个 X(哪怕属性不同)",那它往往是实体
  • 如果你在讨论中频繁使用"只要值相同就一样",那它往往是值对象

伪代码示例:实体围绕"标识 + 状态机 + 行为"

下面的伪代码形状展示了一个典型订单实体/聚合根的结构(包含 addItem/pay 等行为,以及 OrderStatus 状态机)。

text 复制代码
class Order {                       // Entity / Aggregate Root
  orderNumber: OrderNumber          // Identity (VO)
  customerId: CustomerId            // VO
  status: OrderStatus               // State machine (VO-like)
  items: List<OrderItem>            // VO collection

  addItem(item):
    require status.canPay()
    require items.size < MAX_ORDER_LINES
    items.add(item)

  pay():
    require OrderPaymentSpecification().isSatisfiedBy(this)
    status = status.transitionToPaid()
    domainEvents.add(OrderPaidEvent(...))
}

实体的相等性(Equality)约定

课堂统一口径建议:

  • 实体相等性只看标识OrderNumber 一样就是同一订单
  • 值对象相等性看所有属性值OrderNumber("ORDER-...") 值相同就是同一个值

这会直接影响:

  • 你怎么写 equals/hashCode
  • 你如何去重、如何做集合操作(Set/Map)
  • 你如何在日志/事件/接口中传递身份信息

常见误区

  • 误区 1:把数据库主键当领域标识:导致"业务上订单号变化/迁移/合并"时建模困难;讨论也会被技术细节带跑
  • 误区 2:实体没有行为,只有 getter/setter:业务规则散落在 Application Service / Controller,模型贫血
  • 误区 3:实体相等性用所有字段比较:任何字段变化都会让"同一个实体"在集合里变成"另一个对象"

课堂练习

以"订单"为例,请完成以下建模判断题(写出理由):

  1. Order 是实体还是值对象?它的标识是什么?
  2. OrderNumber 是实体还是值对象?为什么不把它做成 String
  3. 如果"客户可以修改收货地址",Address 更像实体还是值对象?(提示:看是否需要独立标识与生命周期)

自测题

  1. 你如何用一句话区分实体与值对象?
  2. 为什么说"实体不是数据库表的一行"?请举出一个业务规则的例子。
  3. 在你的项目里,最容易被误建成实体的值对象是什么?

延伸阅读

相关推荐
机器视觉的发动机16 小时前
AI算力中心的能耗挑战与未来破局之路
开发语言·人工智能·自动化·视觉检测·机器视觉
铁蛋AI编程实战16 小时前
通义千问 3.5 Turbo GGUF 量化版本地部署教程:4G 显存即可运行,数据永不泄露
java·人工智能·python
HyperAI超神经16 小时前
在线教程|DeepSeek-OCR 2公式/表格解析同步改善,以低视觉token成本实现近4%的性能跃迁
开发语言·人工智能·深度学习·神经网络·机器学习·ocr·创业创新
晚霞的不甘16 小时前
CANN 编译器深度解析:UB、L1 与 Global Memory 的协同调度机制
java·后端·spring·架构·音视频
SunnyDays101116 小时前
使用 Java 冻结 Excel 行和列:完整指南
java·冻结excel行和列
R_.L16 小时前
【QT】常用控件(按钮类控件、显示类控件、输入类控件、多元素控件、容器类控件、布局管理器)
开发语言·qt
C澒16 小时前
前端分层架构实战:DDD 与 Clean Architecture 在大型业务系统中的落地路径与项目实践
前端·架构·系统架构·前端框架
Zach_yuan16 小时前
自定义协议:实现网络计算器
linux·服务器·开发语言·网络
摇滚侠16 小时前
在 SpringBoot 项目中,开发工具使用 IDEA,.idea 目录下的文件需要提交吗
java·spring boot·intellij-idea
云姜.16 小时前
java多态
java·开发语言·c++