[譯文] 實體與值對象到底是不是一回事?


原文: Is Entity the same as Value Object?

In this post, we’ll discuss an interesting question about whether the concepts of Entity and Value Object are the same.

在這篇文章中, 我們將討論一個有趣的問題, 關於實體與值對象的概念是否相同.

I wrote a lot about entities and value objects. Here’s the go-to post if you need to learn more about what they are and the differences between them: Entity vs Value Object: the ultimate list of differences. And to this date, I find interesting angles to look at these concepts from.

我寫了一堆關於實體和值對象的文章. 如果你需要了解它們是什么以及它們之間的區別, 可參考下這篇文章: 實體 vs 值對象: 終極差異清單. 到目前為止, 我發現了一些有趣的角度來探索這些概念.

This one comes from Panos Kousidis who asked a insightful question in the comments to one of my posts about value objects:

這個問題來來源於 Panos Kousidis, 他在我的一篇 關於值對象的一篇文章 的評論中提出了一個極為深刻的問題:

Can we consider an "Entity" as a "ValueObject" that compares only its Id for equality? Can this result in defining the base entity class as

我們是否可以考慮將 實體 視作為 值對象, 僅比較它們的 Id 是否相等? 可否將實體基類定義為:

public abstract class Entity : ValueObject
{
   public int Id { get; protected set; }

   protected override IEnumerable<object> GetEqualityComponents()
   {
       yield return Id;
   }
}

This is a deep question which doesn’t have a quick answer, so let’s break it down into two parts. Here’s what differentiates entities from value objects (again, taken from this article):

這是個很難回答的問題, 所以我們將其分為兩部分. 這里有關於實體和值對象區別的文章(還是這里, 取自 這篇文章):

  • Identity comparison
  • 標識符比較.
  • Immutability
  • 不可變性.
  • History preservation*
  • 歷史維持*.

(譯者注: History preservation, 歷史維持. 這個翻譯是 茶姨 提供的, 我在 領域驅動設計:軟件核心復雜性應對之道(修訂版) 並沒找到對應翻譯, 還可譯為 "歷史保存", 大概意思是實體的狀態變更的記錄將會保存下來.)

Let’s review the treatment of entities as value objects with regards to each of these two items.

讓我們重新看下, 將實體視為值對象的處理方法, 其中涉及到這兩項 (作者指的是 實體值對象) 中的每一項.

標識符比較 (Identity comparison)

Identity comparison defines how two instances of a class compare to each other.

標識符比較 定義類的兩個實例如何相互比較彼此.

Entities are compared by their identifiers. Two objects are deemed equal if they have the same Id:

實體通過它們的標識符在彼此之間進行比較. 對於兩個對象, 若他們擁有相同的 Id, 則被認為是相等的.

Identifier equality

Identifier equality (標識符的相等)

Value objects are compared by their content. Two value objects are deemed the same if their contents match:

值對象則根據他們的內容去比較. 若兩個值對象的內容完全相同, 則被認為相等.

Identifier equality

Structural equality (結構的相等)

Note that although you usually compare value objects by all of their contents, it doesn’t have to always be the case. Some fields might not matter for identity comparison.

注意, 盡管通常通過值對象的內容比較來比較他們, 但可不一定總是這樣. 某些字段在比較標識符的時候可能並不重要.

An example is the Error class I brought up in a recent article:

一個例子是這個我在 最近的一篇文章 中提到的 Error 類:

public sealed class Error : ValueObject
{
    public string Code { get; }
    public string Message { get; }

    internal Error(string code, string message)
    {
        Code = code;
        Message = message;
    }

    protected override IEnumerable<object> GetEqualityComponents()
    {
        yield return Code; // the only field used for comparison (唯一用於比較的字段).
    }
}

This class contains two fields:

此類包含兩個字段 (此處有爭議, 上文代碼里應為屬性, 但作者在此文中經常混用 field(字段)property(屬性)):

  • Code — this is what defines an error,
  • Message — for additional debug information just for developers.
  • Code —  這個定義了錯誤碼,
  • Message —  僅為開發者附加的調試信息.

If you pass errors to external systems, those systems shouldn’t ever bind to error messages, only to their codes. This is why the Error class uses only the Code field for identity comparison: changes in debug messages don’t matter; two errors with the same code are treated as the same error even if their messages differ.

如果你將錯誤傳遞給外部系統, 那么這些系統不應該與錯誤信息綁定, 而應該僅僅綁定到給他們錯誤碼. 這就是為什么 Error 類僅使用 Code 字段作為標識符比較: 調試信息的變化無關緊要. 具有相同錯誤碼的兩個錯誤被認為是相同的錯誤, 即使它們的消息不同.

This is where Panos Kousidis' question comes from too. If you can exclude some fields from a value object’s identity comparison, can you also exclude all of them (except for the Id) and end up with the code like the following?

這也就是 Panos Kousidis 的問題根源. 如果你能從值對象的標識符比較中排除一些字段, 那么是否還能排除除了 Id 之外所有字段, 直到它們的類似於下面的代碼?

public abstract class Entity : ValueObject
{
    public int Id { get; protected set; }

    protected override IEnumerable<object> GetEqualityComponents()
    {
        yield return Id;
    }
}

public class Customer : Entity
{
    public string Name { get; protected set; }
    public string Email { get; protected set; }
}

You definitely can, I don’t see any reason why not. So, from the identity comparison perspective, the answer to the question "Can you treat Entity and Value Object as the same concept?" is yes.

你完全可以這么做, 我看不出來有什么理由不可以. 因此, 從標識符比較的視角, "是否可以將實體和值對象視為相同的概念?" 的答案是 "YES".

不可變性 (Immutability)

In terms of immutability, the difference between entities and value object is that value objects are immutable, whereas entities are almost always mutable. You don’t modify a value object; instead, you create a new one and replace the old instance with it.

在不可變性上, 實體與值對象的區別在於值對象是不可變的, 而實體幾乎總是可變的. 不需要修改值對象; 而是創建一個值對象的新實例去替換舊實例.

One could argue that immutability isn’t a defining property of a value object either. You could even apply the same line of reasoning as with identity comparison and say that what matters is immutability of the fields that form the value object’s identity, and that all other fields can be left mutable. In the example with the Error class, that would mean being able to change the Message field, but not Code.

有人可能會說, 不可變性也不是值對象的屬性定義. 你甚至可以應用同樣的推理作為 標識符比較, 並說重要的是構成值對象的標識符字段的不可變性, 而其它所有的字段可以保持可變的. 在 Error 類的示例中, 意味着可以修改 Message 字段, 但是不能修改 Code 字段.

And it’s true that fields that form the object’s identity must not change. This requirement works similarly for entities and value objects:

的確, 構成對象的標識符字段不能變更, 這一要求同樣適用於實體和值對象:

  • The modification of an entity’s Id field would turn that entity into a different one. Thus, such a modification is prohibited.
  • 修改實體的 Id 字段會將該實體變成另外一個實體. 因此, 這種修改是被禁止的.
  • Similarly, the modification of fields that form a value object’s identity would, too, turn that value object into a different one.
  • 同樣地, 對構成值對象的標識符字段修改也會將該值對象轉變成另外一個不同的值對象.

But what about the remaining fields? If we can change an entity’s properties (except for the Id one), can’t we also change the fields of a value object, as long as they aren’t part of its identity?

但是剩余其它的字段呢? 如果我們能改變一個實體除 Id 外的屬性, 那么我們是否也可以修改值對象的字段, 只要這些字段不是值對象標識符的一部分?

On the surface, it looks like we can, but this line of reasoning falls apart when you take into account the 3rd component that differentiates entities from value objects: history preservation.

從表面上看, 我們好像可以這樣子做, 但是當考慮到實體與值對象的第三個區別: 歷史維持 時, 這種推理就經不起推敲了.

歷史維持 (History preservation)

History preservation is whether or not an object has a history in your domain model.

歷史維持 指的是對象在域模型中是否具有歷史記錄.

Entities have such a history (even though you might not store it explicitly). In other words, entities live in a continuum: they are created, modified, and deleted — all at different points in time. Value objects don’t have a history; they are a mere snapshot of some state.

實體就具有這樣的歷史記錄 (即使你可能沒有顯示地存儲它). 換句話說, 實體是連續存在的: 它們在不同的時間點被創建, 修改和刪除. 值對象沒有歷史, 它們僅僅是某些狀態的快照.

The modification of a value object implicitly extends its lifetime beyond just being a snapshot. Such a modification assumes the value object also has a history, which goes against the requirement of not preserving history in value objects.

值對象的修改隱式地延長了其生存期, 而不僅僅是作為快照. 這樣的修改假設值對象也具有歷史記錄, 但是這違反了值對象中不保留歷史記錄的要求.

History preservation is what answers the question of "Can you treat Entity and Value Object as the same concept?". That answer is no.

歷史維持是對 "可以將實體對象和值對象視為同一個概念?" 這一問題的回答, 答案是否定的.

總結 (Summary)

The answer to the question of "Can we consider an entity as a value object that compares only its Id for equality?" boils down to three parts:

"我們是否可以考慮將 實體 視作為 值對象, 僅比較它們的 Id 是否相等?" 這個問題的回答可以歸結為三個部分:

  • In terms of identity comparison, the answer is yes.
  • 就比較標識符而言, 答案是可以.
  • In terms of immutability, the answer is yes.
  • 就不可變性而言, 答案是可以.
  • In terms of history preservation, the answer is no.
  • 就歷史保護而言, 答案是不能.

Thus, the overall answer is also no.

因此, 總的答案也是不能的.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM