ddd-entity
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOne-line summary
一句话总结
An entity is a domain object identified by who it is, not by what it contains — its identity is stable across attribute changes and across time.
Entity 是由 who it is(它是谁)而不是 what it contains(它包含什么)来标识的 domain object——其 identity 在 attributes 发生变化以及时间推移时都保持稳定。
When to use this skill
何时使用此 skill
- Modeling something tracked over time: ,
Customer,Order,Account,Shipment.Subscription - Two instances with identical attributes are still distinct things ("two customers named John Smith are not the same customer").
- A concept has a lifecycle — created, modified, archived, deleted — and the same conceptual instance persists across those states.
- 对需要随时间跟踪的对象建模:、
Customer、Order、Account、Shipment。Subscription - 两个实例即使具有完全相同的 attributes,仍然是不同的对象(“两个名为 John Smith 的 Customer 不是同一个 Customer”)。
- 某个 concept 具有 lifecycle——创建、修改、归档、删除——并且同一个 conceptual instance 会持续存在于这些状态之中。
When NOT to use this skill
何时不要使用此 skill
- The concept is fully described by its attributes with no identity → use .
ddd-value-object - The "identity" is just a database autoincrement with no domain meaning → that suggests the concept might actually be a value object that the persistence layer is identifying for storage reasons.
- The concept exists only inside a single aggregate and is never referenced from outside → it may still be an entity, but reconsider whether it needs to be modeled separately at all.
- 该 concept 完全由其 attributes 描述且没有 identity → 使用 。
ddd-value-object - 所谓的“identity”只是 database autoincrement ID,而不具有 domain 意义 → 这可能意味着该 concept 实际上是一个 Value Object,只是 persistence layer 为了存储而将其标识出来。
- 该 concept 仅存在于单个 aggregate 内部,并且从不被外部引用 → 它仍然可能是 Entity,但应重新考虑是否有必要将其单独建模。
Core content
核心内容
Identity is the distinguishing feature. An entity's identity is assigned (often as a UUID, a business identifier like a customer number, or a natural key) and stable — it does not change when attributes change. Equality is by identity: two entities are equal if and only if their identifiers match, regardless of every other field.
Entities have lifecycles. They are created (often via a factory), modified through methods that maintain invariants, possibly archived, and possibly deleted. Throughout that lifecycle the identity remains the same.
Entities expose behavior, not just data. A entity might have methods like , , . Each of those methods is responsible for enforcing the entity's invariants — the customer's state is never inconsistent.
CustomerchangeAddresscloseAccountdeactivateIdentity 是区分 Entity 的核心特征。Entity 的 identity 是被 assigned 的(通常采用 UUID、customer number 之类的 business identifier,或者 natural key),并且保持 stable——当 attributes 发生变化时,它不会改变。相等性由 identity 决定:无论其他所有字段如何,两个 Entity 当且仅当其 identifiers 匹配时才相等。
Entity 拥有 lifecycle。它们被创建(通常通过 factory),通过维护 invariants 的方法进行修改,可能被 archive,也可能被 delete。在整个 lifecycle 中,identity 始终保持不变。
Entity 暴露的是 behavior,而不只是 data。例如, Entity 可能包含 、、 等方法。每个方法都负责维护该 Entity 的 invariants——Customer 的状态永远不会处于不一致状态。
CustomerchangeAddresscloseAccountdeactivateDecision heuristics
决策启发式
- Entity if you need to track its history or refer to "the same one" later.
- Value object if you would happily swap one instance for another with the same attributes.
- If a candidate concept is an entity but has no behavior beyond getters/setters, push back: either the entity is anemic (add behavior), or it is misclassified (it might really be a value object).
- Identity is assigned, not derived from attributes. If you find yourself deriving identity from fields, you are likely modeling a value object.
- 如果需要追踪对象的 history,或者之后需要引用“同一个”对象,则应使用 Entity。
- 如果可以将一个实例替换为另一个具有相同 attributes 的实例而不会产生问题,则应使用 Value Object。
- 如果一个 candidate concept 是 Entity,但除了 getters/setters 之外没有任何 behavior,则应提出异议:要么该 Entity 是 anemic 的(需要补充 behavior),要么它分类错误(实际上可能是 Value Object)。
- Identity 是被 assigned 的,而不是从 attributes 推导出来的。如果发现通过 fields 推导 identity,那么所建模的对象很可能实际上是 Value Object。
Anti-patterns
反模式
- Modeling every domain object as an entity, including ones that have no inherent identity ("entity explosion").
- Entity with no behavior — an "anemic entity" that is just fields with getters. See .
ddd-anti-patterns - Replacing identity equality with attribute equality (a language adapter pitfall — Kotlin does this by default).
data class - Treating a database row's autoincrement ID as if it were the domain's identity.
- 将每个 domain object 都建模为 Entity,包括那些没有 inherent identity 的对象(“entity explosion”)。
- 没有 behavior 的 Entity——即只有 fields 和 getters 的“anemic entity”。参见 。
ddd-anti-patterns - 使用 attribute equality 代替 identity equality(language adapter pitfall——Kotlin 默认采用前一种方式)。
data class - 将 database row 的 autoincrement ID 当作 domain 的 identity。
See also
相关内容
- — the opposite case; concepts without identity.
ddd-value-object - — entities often serve as aggregate roots.
ddd-aggregate - — for creating entities with non-trivial construction.
ddd-factory - — for loading and saving entities by identity.
ddd-repository - — anemic entities, primitive obsession in identifiers.
ddd-anti-patterns
- ——相反的情况;没有 identity 的 concepts。
ddd-value-object - ——Entity 通常作为 aggregate roots。
ddd-aggregate - ——用于以非平凡方式创建 Entity。
ddd-factory - ——根据 identity 加载和保存 Entity。
ddd-repository - ——anemic Entity、identifiers 中的 primitive obsession。
ddd-anti-patterns
References
参考资料
- Evans, Domain-Driven Design (2003), Ch. 5 (A Model Expressed in Software).
- Evans,Domain-Driven Design(2003),第 5 章(A Model Expressed in Software)。