原文: 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 (識別符號的相等)
Value objects are compared by their content. Two value objects are deemed the same if their contents match:
值物件則根據他們的內容去比較. 若兩個值物件的內容完全相同, 則被認為相等.

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
Errorclass 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
Errorclass uses only theCodefield 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
Errorclass, that would mean being able to change theMessagefield, but notCode.
有人可能會說, 不可變性也不是值物件的屬性定義. 你甚至可以應用同樣的推理作為 識別符號比較, 并說重要的是構成值物件的識別符號欄位的不可變性, 而其它所有的欄位可以保持可變的. 在 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.
因此, 總的答案也是不能的.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/6677.html
標籤:其他
上一篇:[譯文] C# 8 已成舊聞, 向前, 抵達 C# 9!
下一篇:Theia架構
