DDD实践疑问:产品分类应设为值对象还是实体?
产品目录上下文里Product Category的DDD定位与持久化方案
首先明确DDD里实体和值对象的核心判断依据:
- 实体:拥有唯一标识,具备独立生命周期,标识不变则实体身份不变,属性可变更。
- 值对象:无唯一标识,属性完全相等则视为同一对象,通常设计为不可变(属性变更等价于生成新的值对象)。
针对你的场景,分两种业务情况来定:
场景1:分类是独立维护的业务实体(需同步变更到关联产品)
如果你的业务要求:
- 运营可以独立对分类做CRUD(比如新增分类、修改分类名称、禁用分类)
- 分类变更后,已关联该分类的产品要同步显示最新的分类信息(比如分类改名后,所有该分类下的产品都显示新名称)
这种情况下,Category是实体,且建议作为独立聚合根:
- 它有自己的唯一标识(如
category_id),具备独立的生命周期(从创建到禁用/删除) - 产品(Product聚合根)仅通过分类的ID来关联,而不是直接持有分类对象(避免跨聚合耦合)
对应持久化方式:
- 数据库层面:
- 新建
category表,存储分类的标识(id)、名称(name)、状态(status)、层级(如parent_id)等字段 product表中存储category_id作为外键,关联category表
- 新建
- 领域层:
- Product聚合根持有
CategoryId值对象(封装分类ID),而非Category实体 - 当需要展示产品分类信息时,通过CategoryRepository查询对应的Category聚合根
- Product聚合根持有
场景2:分类是产品的描述性属性(无需同步变更)
如果你的业务规则是:
- 分类列表仅作为产品创建/编辑时的选择项,分类的后续修改不影响已关联的产品(比如选了“电子产品”后,分类改名成“数码产品”,老产品仍显示“电子产品”)
这种情况下,Category是值对象:
- 它没有独立的生命周期,仅作为产品的一部分属性存在
- 产品中的Category值对象是创建时从分类列表中复制的属性快照,后续分类列表的变化与已存在的产品无关
对应持久化方式:
- 数据库层面:
- 方案1:直接在
product表中存储分类的核心属性(如category_code、category_name),无需关联分类表 - 方案2:若需统一维护分类选择列表,可建
category_dict表,但product表存储的是选中时的属性副本(而非外键),确保产品数据不受分类表修改影响
- 方案1:直接在
- 领域层:
- 设计
Category值对象,包含code、name等属性,且设为不可变(如需修改产品分类,需替换为新的Category值对象)
- 设计
关键决策点
核心判断标准是分类的变更是否需要同步到已关联的产品:
- 若需要同步 → 实体(独立聚合根)
- 若不需要同步 → 值对象
内容的提问来源于stack exchange,提问作者Jester1811
相关产品推荐
相关产品推荐

