ddd-entity

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

One-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
Customer
entity might have methods like
changeAddress
,
closeAccount
,
deactivate
. Each of those methods is responsible for enforcing the entity's invariants — the customer's state is never inconsistent.
Identity 是区分 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。例如,
Customer
Entity 可能包含
changeAddress
、
closeAccount
、
deactivate
等方法。每个方法都负责维护该 Entity 的 invariants——Customer 的状态永远不会处于不一致状态。

Decision 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
    data class
    does this by default).
  • 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

相关内容

  • ddd-value-object
    — the opposite case; concepts without identity.
  • ddd-aggregate
    — entities often serve as aggregate roots.
  • ddd-factory
    — for creating entities with non-trivial construction.
  • ddd-repository
    — for loading and saving entities by identity.
  • ddd-anti-patterns
    — anemic entities, primitive obsession in identifiers.
  • ddd-value-object
    ——相反的情况;没有 identity 的 concepts。
  • ddd-aggregate
    ——Entity 通常作为 aggregate roots。
  • ddd-factory
    ——用于以非平凡方式创建 Entity。
  • ddd-repository
    ——根据 identity 加载和保存 Entity。
  • ddd-anti-patterns
    ——anemic Entity、identifiers 中的 primitive obsession。

References

参考资料

  • Evans, Domain-Driven Design (2003), Ch. 5 (A Model Expressed in Software).
  • Evans,Domain-Driven Design(2003),第 5 章(A Model Expressed in Software)。