簡體   English   中英

值與實體對象(域驅動設計)

[英]Value vs Entity objects (Domain Driven Design)

我剛剛開始閱讀 DDD。 我無法完全掌握實體與值對象的概念。有人可以解釋當值對象被設計為實體對象時系統可能面臨的問題(可維護性、性能等)嗎? 例子會很棒......

歸結為本質區別,身份對實體很重要,但對值對象無關緊要。 例如,某人的姓名是一個值對象。 客戶實體可能由客戶名稱(值對象)、List<Order> OrderHistory(實體列表)和可能的默認地址(通常是值對象)組成。 客戶實體將有一個 ID,每個訂單都有一個 ID,但名稱不應; 通常,無論如何,在對象模型中,地址的身份可能無關緊要。

值對象通常可以表示為不可變對象; 更改值對象的一個​​屬性本質上會破壞舊對象並創建一個新對象,因為您不像內容那樣關心身份。 正確地,只要對象的屬性與另一個實例的屬性相同,Name 上的 Equals 實例方法就會返回“true”。

但是,更改諸如 Customer 之類的實體的某些屬性並不會破壞該客戶; Customer 實體通常是可變的。 身份保持不變(至少在對象被持久化后)。

您可能在沒有意識到的情況下創建了值對象; 任何時候你通過創建一個細粒度的類來表示實體的某些方面,你就有了一個值對象。 例如,一個類 IPAddress 對有效值有一些限制,但由更簡單的數據類型組成,將是一個值對象。 EmailAddress 可以是字符串,也可以是具有自己的行為集的值對象。

很有可能即使在您的數據庫中具有標識的項目在您的對象模型中也沒有標識。 但最簡單的情況是將一些有意義的屬性組合在一起。 當您可以將它們組合為 Customer.Name 時,您可能不想擁有 Customer.FirstName、Customer.LastName、Customer.MiddleInitial 和 Customer.Title; 當您考慮持久性時,它們可能會成為您數據庫中的多個字段,但您的對象模型並不關心。

任何由其所有屬性共同定義的對象都是值對象。 如果任何屬性發生變化,您將擁有一個值對象的新實例。 這就是為什么值對象被定義為不可變的。

如果對象沒有完全由其所有屬性定義,則存在組成對象標識的屬性子集。 其余屬性無需重新定義對象即可更改。 這種對象不能在 immutable 中定義。

一種更簡單的區分方法是將值對象視為永遠不會改變的靜態數據,將實體視為在應用程序中發展的數據。

值類型:

  • 值類型本身不存在,取決於實體類型。
  • 值類型對象屬於實體類型對象。
  • 值類型實例的生命周期受擁有實體實例的生命周期的限制。
  • 三種值類型:基本(原始數據類型)、復合(地址)和集合(映射、列表、數組)

實體:

  • 實體類型可以獨立存在(Identity)
  • 實體有自己的生命周期。 它可以獨立於任何其他實體而存在。
  • 例如:人、組織、學院、手機、家庭等。每個對象都有自己的身份

我不知道以下是否正確,但我會說,在 Address 對象的情況下,我們希望將其用作值對象而不是實體,因為對實體的更改將反映在所有鏈接對象上(例如一個人)。

以這種情況為例:您和其他一些人住在自己的房子里。 如果我們將 Entity 用於 Address,我認為所有 Person 對象都鏈接到一個唯一的 Address。 如果一個人搬出去,你想更新他的地址。 如果您要更新地址實體的屬性,則所有人都將擁有不同的地址。 在值對象的情況下,我們將無法編輯地址(因為它是不可變的)並且我們將被迫為該人提供一個新地址。

這聽起來對嗎? 我必須說,在閱讀了 DDD 書之后,我仍然/仍然對這種差異感到困惑。

更進一步,這將如何在數據庫中建模? 您是否將 Address 對象的所有屬性都作為 Person 表中的列,或者您是否會創建一個單獨的 Address 表,該表也將具有唯一標識符? 在后一種情況下,住在同一棟房子里的人每個人都有一個不同的 Address 對象實例,但這些對象除了 ID 屬性外都是相同的。

地址可以是實體或值對象,這取決於繁忙的進程。 地址對象可以是快遞服務應用程序中的實體,但地址可以是其他應用程序中的值對象。 在快遞申請中地址對象的身份問題

3 EntitiesValue Objects區別

  • 標識符 vs 結構相等:實體有標識符,如果實體有相同的標識符,則實體是相同的。 超越手上的值對象具有結構相等性,當所有字段都相同時,我們認為兩個值對象相等。 值對象不能有標識符。

  • 可變性與不變性:值對象是不可變的數據結構,而實體在其生命周期中會發生變化。

  • Lifespan:值對象應該屬於實體

我在另一個線程中詢問了這個問題,我想我仍然感到困惑。 我可能會將性能考慮與數據建模混淆。 在我們的編目應用程序中,客戶在需要時不會更改。 這聽起來很愚蠢 - 但是客戶數據的“讀取”遠遠超過“寫入”,並且由於許多 Web 請求都在訪問“活動集”對象,因此我不想一次又一次地加載客戶。 所以我為 Customer 對象走上了一條不可變的道路——加載它,緩存它,並為 99% 的(多線程)請求提供相同的服務,希望看到 Customer。 然后,當客戶更改某些內容時,請“編輯器”創建新客戶並使舊客戶無效。

我擔心的是,如果許多線程看到同一個客戶對象並且它是可變的,那么當一個線程開始更改時,其他線程就會發生混亂。

我現在的問題是,1) 這是否合理,以及 2) 如何最好地做到這一點,而無需復制大量有關屬性的代碼。

用一個非常簡單的句子我可以說,我們有三種類型的平等:

  • 標識符相等:一個類有 id 字段,兩個對象與它們的 id 字段值進行比較。
  • 引用相等:如果對兩個對象的引用在內存中具有相同的地址。
  • 結構相等:如果兩個對象的所有成員都匹配,則它們相等。

標識符相等僅指實體,結構相等僅指值對象。 事實上,值對象沒有 id,我們可以互換使用它們。 值對象也必須是不可變的,實體可以是可變的,值對象在數據庫中不會有表。

一個實體:

  • 有身份

  • 包含值對象

  • 可能包含其他實體

  • 可以是可變的

一個值對象:

  • 沒有身份

  • 必須是不可變的

考慮以下來自Wikipedia 的示例,以便更好地理解值對象和實體之間的區別:

價值對象:人們在兌換美元鈔票時,一般不區分每張獨特的鈔票; 他們只關心美元鈔票的面值。 在這種情況下,美元鈔票是值對象。 但是,美聯儲可能會關注每張獨特的鈔票; 在這種情況下,每項法案都是一個實體。

實體:大多數航空公司在每個航班上都唯一區分每個座位。 在這種情況下,每個座位都是一個實體。 但是,西南航空、易捷航空和瑞安航空不區分每個座位; 所有座位都一樣。 在這種情況下,座位實際上是一個值對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM