値とエンティティオブジェクト(ドメイン駆動設計)


90

DDDを読み始めたばかりです。EntityオブジェクトとValueオブジェクトの概念を完全に理解できません。ValueオブジェクトがEntityオブジェクトとして設計されているときにシステムが直面する可能性のある問題(保守性、パフォーマンスなど)を誰かに説明できますか?例は素晴らしいでしょう...


2
ここで私は、両者の違いのフル(IMO)のリストを書いた:enterprisecraftsmanship.com/2016/01/11/...
ウラジミール

回答:


108

本質的な違いに整理すると、アイデンティティはエンティティにとって重要ですが、値オブジェクトにとっては重要ではありません。たとえば、誰かの名前は値オブジェクトです。Customerエンティティは、顧客の名前(値オブジェクト)、List <Order> OrderHistory(エンティティのリスト)、およびおそらくデフォルトのアドレス(通常は値オブジェクト)で構成されます。Customer EntityにはIDがあり、各注文にはIDがありますが、Nameにはありません。一般的に、オブジェクトモデル内では、アドレスのIDはおそらく重要ではありません。

値オブジェクトは通常、不変オブジェクトとして表すことができます。値オブジェクトの1つのプロパティを変更すると、本質的に古いオブジェクトが破棄され、新しいオブジェクトが作成されます。これは、コンテンツほどアイデンティティに関心がないためです。正しくは、オブジェクトのプロパティが別のインスタンスのプロパティと同一である限り、NameのEqualsインスタンスメソッドは「true」を返します。

ただし、顧客などのエンティティの一部の属性を変更しても、顧客は破壊されません。Customerエンティティは通常、変更可能です。IDは同じままです(少なくともオブジェクトが永続化されると)。

おそらくそれを実現せずに値オブジェクトを作成します。きめの細かいクラスを作成してエンティティのある側面を表現しているときはいつでも、値オブジェクトを持っています。たとえば、有効な値にいくつかの制約がありますが、より単純なデータ型で構成されるクラスIPAddressは、値オブジェクトになります。EmailAddressは文字列にすることも、独自の動作セットを持つ値オブジェクトにすることもできます。

データベースにIDがあるアイテムでさえ、オブジェクトモデルにIDがない可能性があります。しかし、最も単純なケースは、一緒に意味をなすいくつかの属性の複合です。Customer.Nameとして一緒に構成できる場合、Customer.FirstName、Customer.LastName、Customer.MiddleInitial、Customer.Titleを一緒に構成したくない場合があります。永続性について考えるときには、おそらくデータベースの複数のフィールドになりますが、オブジェクトモデルは関係ありません。


非共有の可変オブジェクトはどこに収まりますか?宇宙全体でオブジェクトへの参照が1つしか存在しない場合、オブジェクトが変更可能であっても、オブジェクトのIDは関係ありません。私が見ると、その参照が変更に使用されていなくても変更できる状態の側面を観察するために使用できる参照が存在する場合、物はエンティティです。モノが外の世界に接続されておらず、不変であるか、ユニバース内のどこかにそれへの参照が1つしか存在しない場合、上記のシナリオは発生せず、それは値です。
スーパーキャット2014

のようなものはint[1]、非共有の変更可能な値、共有可能な不変の値(参照を保持するものが何も書き込まれない場合)、またはエンティティ(2つ以上の参照が存在し、そのうちの1つが書き込みに使用される場合)他を使用して読み取ることができる値)。残念ながら、可変値をカプセル化するクラスオブジェクトが誤ってエンティティに変換されるのを防ぐためのJavaまたは.NETの言語サポートがないことを知っています。
スーパーキャット2014

@supercat、直接の単純なサポートを意味しない場合は同意しますが、これは、コンストラクターへのパブリックアクセスを排除し、静的ファクトリーのみを使用して新しいインスタンスを作成し、読み取り専用プロパティを介して状態へのすべてのアクセスを制限する(セッターなし) 。
Charles Bretana、2014年

36

すべての属性によって集合的に定義されるオブジェクトは、値オブジェクトです。属性のいずれかが変更された場合、値オブジェクトの新しいインスタンスがあります。これが、値オブジェクトが不変として定義されている理由です。

オブジェクトがそのすべての属性によって完全に定義されていない場合は、オブジェクトのIDを構成する属性のサブセットがあります。残りの属性は、オブジェクトを再定義せずに変更できます。この種類のオブジェクトは、不変では定義できません。

区別するためのより簡単な方法は、値オブジェクトを決して変更されない静的データと見なし、エンティティをアプリケーションで進化するデータと見なすことです。


7

値のタイプ:

  • 値型はそれ自体では存在せず、エンティティ型に依存します。
  • 値タイプオブジェクトはエンティティタイプオブジェクトに属しています。
  • 値タイプのインスタンスの寿命は、所有するエンティティインスタンスの寿命によって制限されます。
  • 3つの値タイプ:Basic(primitive datatypes)、Composite(Address)およびCollection(Map、List、Arrays)

エンティティ:

  • エンティティタイプは独自に存在できます(Identity)
  • エンティティには独自のライフサイクルがあります。他のエンティティとは独立して存在する場合があります。
  • 例:人、組織、大学、モバイル、自宅など。すべてのオブジェクトには独自のIDがあります。

DDDとは関係ありません:(
HydTechie

6

以下が正しいかどうかはわかりませんが、Addressオブジェクトの場合は、エンティティの変更がすべてのリンクされたオブジェクトに反映されるため、EntityではなくValueオブジェクトとして使用したいと思います(たとえば、Person)。

この場合を考えてみましょう:あなたは家に他の人と住んでいます。Entity for Addressを使用する場合、すべてのPersonオブジェクトがリンクする一意のアドレスが1つあると私は主張します。1人が引っ越した場合、その人の住所を更新します。住所エンティティのプロパティを更新すると、すべての人が異なる住所を持つことになります。値オブジェクトの場合、(不変であるため)アドレスを編集できず、その個人に新しいアドレスを提供する必要があります。

これは正しい音ですか?DDDの本を読んだ後も、私はこの違いについてまだ混乱していたと言わざるを得ません。

さらに一歩進んで、これはデータベースでどのようにモデル化されますか?Personオブジェクトの列としてAddressオブジェクトのすべてのプロパティを持っていますか、それとも一意の識別子も持つ別個のAddressテーブルを作成しますか?後者の場合、同じ家に住んでいる人々はそれぞれ、Addressオブジェクトの異なるインスタンスを持っていますが、それらのオブジェクトはIDプロパティを除いて同じです。


1
「このケースを考えてください。あなたは家に他の人と住んでいます。住所にエンティティを使用する場合、すべてのPersonオブジェクトがリンクする一意の住所が1つあると私は主張します。」私はそれらの人々それぞれがそれ自身のアドレスのインスタンスを持っていると思いますが、彼らは
偶然に偶然

「しかし、それが同じ紙幣であることを意味するものではありません」-これは、紙幣に追加のプロパティを割り当てるかどうかによって異なります(たとえば、発行日、空間内の物理的な場所など)。それ以外の場合は同じです。そして、私はソフトウェアについても同じだと思います:アドレスは、私たちが検討する必要がある/したいプロパティに応じて、同じかそうでないかです。
adrhc

4

addressは、ビジープロセスに依存するエンティティまたは値オブジェクトにすることができます。アドレスオブジェクトは、宅配便サービスアプリケーションではエンティティにすることができますが、他のアプリケーションでは値オブジェクトにすることができます。宅配便アプリケーションでは、住所オブジェクトのアイデンティティが重要です


2

別のスレッドでこれについて質問しましたが、まだ混乱しています。パフォーマンスに関する考慮事項をデータモデリングと混同している可能性があります。私たちのカタログ作成アプリケーションでは、顧客は必要になるまで変更されません。ばかげているように聞こえますが、顧客データの「読み取り」は「書き込み」よりもはるかに多く、多くのWebリクエストがすべて「アクティブセット」のオブジェクトにヒットしているため、顧客を何度​​も何度もロードしたくありません。それで、私はCustomerオブジェクトの不変の道に向かいました-それをロードしてキャッシュし、Customerを表示したい(マルチスレッドの)リクエストの99%に同じものを提供します。次に、顧客が何かを変更した場合、「編集者」に依頼して新しい顧客を作成し、古いものを無効にします。

私の懸念は、多くのスレッドが同じ顧客オブジェクトを参照していて、それが変更可能である場合、1つのスレッドが変更を開始すると、他のスレッドで問題が発生する可能性があります。

私の問題は、1)これは合理的であり、2)プロパティに関する多くのコードを複製せずにこれを実行するための最善の方法です。


1

3区別間Entities及びValue Objects

  • 識別子と構造的等価性:エンティティには識別子があり、エンティティが同じ識別子を持っていれば、エンティティは同じです。手の上にある値オブジェクトは構造的に等しいため、すべてのフィールドが同じ場合、2つの値オブジェクトは等しいと見なされます。値オブジェクトは識別子を持つことができません。

  • 可変性と不変性:値オブジェクトは不変のデータ構造ですが、エンティティは存続期間中に変化します。

  • ライフスパン:値オブジェクトはエンティティに属すべき


1

非常に簡単な文章で言うと、3つのタイプの平等があります。

  • 識別子の等価性:クラスにはIDが登録されており、2つのオブジェクトがIDフィールド値と比較されます。
  • 参照の等価性:2つのオブジェクトへの参照がメモリ内で同じアドレスを持つ場合。
  • 構造的同等性:2つのオブジェクトは、それらのすべてのメンバーが一致する場合に同等です。

識別子の同等性エンティティのみを参照し、構造的同等性は値オブジェクトのみを参照します。実際、値オブジェクトにはIDがなく、それらを交換して使用できます。また、値オブジェクトは不変である必要があり、エンティティは変更可能であり、値オブジェクトはデータベースにテーブルを持ちません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.