DDDを読み始めたばかりです。EntityオブジェクトとValueオブジェクトの概念を完全に理解できません。ValueオブジェクトがEntityオブジェクトとして設計されているときにシステムが直面する可能性のある問題(保守性、パフォーマンスなど)を誰かに説明できますか?例は素晴らしいでしょう...
回答:
本質的な違いに整理すると、アイデンティティはエンティティにとって重要ですが、値オブジェクトにとっては重要ではありません。たとえば、誰かの名前は値オブジェクトです。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を一緒に構成したくない場合があります。永続性について考えるときには、おそらくデータベースの複数のフィールドになりますが、オブジェクトモデルは関係ありません。
int[1]
、非共有の変更可能な値、共有可能な不変の値(参照を保持するものが何も書き込まれない場合)、またはエンティティ(2つ以上の参照が存在し、そのうちの1つが書き込みに使用される場合)他を使用して読み取ることができる値)。残念ながら、可変値をカプセル化するクラスオブジェクトが誤ってエンティティに変換されるのを防ぐためのJavaまたは.NETの言語サポートがないことを知っています。
すべての属性によって集合的に定義されるオブジェクトは、値オブジェクトです。属性のいずれかが変更された場合、値オブジェクトの新しいインスタンスがあります。これが、値オブジェクトが不変として定義されている理由です。
オブジェクトがそのすべての属性によって完全に定義されていない場合は、オブジェクトのIDを構成する属性のサブセットがあります。残りの属性は、オブジェクトを再定義せずに変更できます。この種類のオブジェクトは、不変では定義できません。
区別するためのより簡単な方法は、値オブジェクトを決して変更されない静的データと見なし、エンティティをアプリケーションで進化するデータと見なすことです。
値のタイプ:
エンティティ:
以下が正しいかどうかはわかりませんが、Addressオブジェクトの場合は、エンティティの変更がすべてのリンクされたオブジェクトに反映されるため、EntityではなくValueオブジェクトとして使用したいと思います(たとえば、Person)。
この場合を考えてみましょう:あなたは家に他の人と住んでいます。Entity for Addressを使用する場合、すべてのPersonオブジェクトがリンクする一意のアドレスが1つあると私は主張します。1人が引っ越した場合、その人の住所を更新します。住所エンティティのプロパティを更新すると、すべての人が異なる住所を持つことになります。値オブジェクトの場合、(不変であるため)アドレスを編集できず、その個人に新しいアドレスを提供する必要があります。
これは正しい音ですか?DDDの本を読んだ後も、私はこの違いについてまだ混乱していたと言わざるを得ません。
さらに一歩進んで、これはデータベースでどのようにモデル化されますか?Personオブジェクトの列としてAddressオブジェクトのすべてのプロパティを持っていますか、それとも一意の識別子も持つ別個のAddressテーブルを作成しますか?後者の場合、同じ家に住んでいる人々はそれぞれ、Addressオブジェクトの異なるインスタンスを持っていますが、それらのオブジェクトはIDプロパティを除いて同じです。
別のスレッドでこれについて質問しましたが、まだ混乱しています。パフォーマンスに関する考慮事項をデータモデリングと混同している可能性があります。私たちのカタログ作成アプリケーションでは、顧客は必要になるまで変更されません。ばかげているように聞こえますが、顧客データの「読み取り」は「書き込み」よりもはるかに多く、多くのWebリクエストがすべて「アクティブセット」のオブジェクトにヒットしているため、顧客を何度も何度もロードしたくありません。それで、私はCustomerオブジェクトの不変の道に向かいました-それをロードしてキャッシュし、Customerを表示したい(マルチスレッドの)リクエストの99%に同じものを提供します。次に、顧客が何かを変更した場合、「編集者」に依頼して新しい顧客を作成し、古いものを無効にします。
私の懸念は、多くのスレッドが同じ顧客オブジェクトを参照していて、それが変更可能である場合、1つのスレッドが変更を開始すると、他のスレッドで問題が発生する可能性があります。
私の問題は、1)これは合理的であり、2)プロパティに関する多くのコードを複製せずにこれを実行するための最善の方法です。
3区別間Entities
及びValue Objects
識別子と構造的等価性:エンティティには識別子があり、エンティティが同じ識別子を持っていれば、エンティティは同じです。手の上にある値オブジェクトは構造的に等しいため、すべてのフィールドが同じ場合、2つの値オブジェクトは等しいと見なされます。値オブジェクトは識別子を持つことができません。
可変性と不変性:値オブジェクトは不変のデータ構造ですが、エンティティは存続期間中に変化します。
ライフスパン:値オブジェクトはエンティティに属すべき
非常に簡単な文章で言うと、3つのタイプの平等があります。
識別子の同等性はエンティティのみを参照し、構造的同等性は値オブジェクトのみを参照します。実際、値オブジェクトにはIDがなく、それらを交換して使用できます。また、値オブジェクトは不変である必要があり、エンティティは変更可能であり、値オブジェクトはデータベースにテーブルを持ちません。