41

DDD の値オブジェクトを不変にする理由がわかりません。また、これを簡単に行う方法もわかりません。(問題があれば、C# と Entity Framework に焦点を当てています。)

たとえば、従来の Address 値オブジェクトを考えてみましょう。"123 Main Street " を "123 Main Street " に変更する必要がある場合、myCustomer.Address.AddressLine1 = "123 Main Street" と言う代わりに、まったく新しいオブジェクトを作成する必要があるのはなぜですか? (Entity Frameworkが構造体をサポートしていたとしても、これはまだ問題ですよね?)

値オブジェクトにはアイデンティティがなく、ドメイン オブジェクトの一部であるという考えは理解していますが (私はそう思います)、誰かが不変性が良いことである理由を説明できますか?


編集:ここでの私の最後の質問は、「値オブジェクトに適用される不変性が良いことである理由を誰かが説明できますか?」です。混乱させて申し訳ありません!


EDIT:明確にするために、私はCLR値型(対参照型)について尋ねていません。値オブジェクトのより高いレベルの DDD の概念について質問しています。

たとえば、Entity Framework の不変値型を実装するためのハック的な方法を次に示します: http://rogeralsing.com/2009/05/21/entity-framework-4-immutable-value-objects。基本的に、彼はすべてのセッターを非公開にするだけです。なぜこれを行うのに苦労するのですか?

4

6 に答える 6

56

DDDとは関係のない、スレッドセーフなどに関するクレイジーな答えはすべて無視してください。(スレッドセーフなO / Rマッパーやその他のDDD対応のダルはまだ見たことがありません)

重みの値オブジェクトを想像してみてください。KG値オブジェクトがあるとしましょう。

サンプル(わかりやすくするために編集):

var kg75 = new Weight(75);
joe.Weight = kg75;
jimmy.Weight = kg75;

さて、私たちがそうしたらどうなるでしょう:

jimmy.Weight.Value = 82;

同じオブジェクト参照をまだ使用している場合は、joeの重みも変更されます。ジョーとジミーの両方に75kgを表すオブジェクトを割り当てたことに注意してください。ジミーが体重を増やしたとき、変化したのはkg75オブジェクトではなく、変化したのはジミーの体重です。したがって、82kgを表す新しいオブジェクトを作成する必要があります。

しかし、新しいセッションがあり、ジョーとジミーの両方をクリーンなUoWにロードするとどうなるでしょうか。

 var joe = context.People.Where(p => p.Name = "joe").First();
 var jimmy = context.People.Where(p => p.Name = "jimmy").First();
 jimmy.Weight.Value = 82;

それではどうなるでしょうか。ええと、あなたの場合のEF4は、アイデンティティなしでjoeとjimmyとそれらの重みをロードするので、2つの異なる重みオブジェクトを取得し、jimmysの重みを変更しても、joeの重みは以前と同じになります。

So we would have two different behaviours for the same code. If the object references are still the same, then both joe and jimmy would get a new weight. If joe and jimmy are loaded in a clean uow, only one of them would be affected by the change.

And that would be quite incosistent imo.

By using immutable VO's, you would get the same behavior in both cases and you can still reuse object references for a smaller memory footprint when constructing object graphs.

于 2011-01-03T07:33:16.147 に答える
43

なぜ 6 は不変なのですか?

それを理解すれば、値オブジェクトが不変であるべき理由が理解できます。

編集:ダイアログをこの回答に引き上げます。

66の同一性はそれが表すもの、つまり何かが 6 つある状態によって決定されるため、 は不変です。6それを表すものを変更することはできません。さて、これが値オブジェクトの基本概念です。それらの値は、状態によって決まります。ただし、エンティティはその状態によって決定されません。ACustomerは姓または住所を変更しても、同じままにすることができますCustomer。これが、値オブジェクトが不変であるべき理由です。それらの状態がアイデンティティを決定します。状態が変われば、ID も変わるはずです。

于 2011-01-03T02:13:53.573 に答える
15

私はパーティーに非常に遅れましたが、私自身これについて疑問に思っていました. (コメントをいただければ幸いです。)

ここで明示的に引用されているとは思いませんが、Evans の不変性への言及は、主に共有のコンテキストにあったと思います。

オブジェクトが安全に共有されるためには、不変でなければなりません: 完全な置き換え以外では変更できません。(エバンス p100)

Evan の本には、"Is Address a Value Object? Who's ask?" というサイドバーもあります。

ルームメイトがそれぞれ電気サービスを注文するために電話をかけた場合 (つまり、2 人の顧客が同じ住所を持っていた場合)、会社はそれを認識する必要があります。[So] アドレスはエンティティです。(エバンス p98)

あなたが示した例では、顧客の自宅と勤務先の住所がどちらもメイン ストリート 123 番地であるとします。あなたが説明した修正を行うと、両方のアドレスが変更されますか? もしそうなら、そして私がエヴァンスを正しく読んでいるなら、あなたは本当にエンティティを持っているように聞こえます.

別の例を挙げて、顧客の氏名を表すオブジェクトがあるとします。

public class FullName
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class Customer
{
    public FullName Name { get; set; }
}

値オブジェクトがないと、以下は失敗します。

[Test]
public void SomeTest() {
    var fullname = new FullName { FirstName = "Alice", LastName = "Jones" };
    var customer1 = new Customer { Name = fullname };
    var customer2 = new Customer { Name = fullname };

    // Customer 1 gets married.
    customer1.Name.LastName = "Smith";

    // Presumably Customer 2 shouldn't get their name changed.
    // However the following will fail.
    Assert.AreEqual("Jones", customer2.Name.LastName);
}

一般的な利点に関しては、DDD では、値オブジェクトの実際の利点は何ですか? . 特に、作成時に VO を検証するだけで済みます。それを行うと、それが常に有効であることがわかります。

于 2011-02-08T08:32:54.080 に答える
5

これは完全な答えではないかもしれません。不変性の利点に関するあなたの質問に答えるだけです。

  1. 不変オブジェクトはスレッドセーフであるためです。状態を変更できないため、スレッドの干渉によって破損したり、矛盾した状態で観察されたりすることはありません。
  2. 不変オブジェクトへの参照は、構築後は状態を変更できないため、コピーやクローンを作成することなく、簡単に共有またはキャッシュできます。
  3. 不変性のその他の利点については、こちらを参照してください (LBushkin の回答) 文字列が不変である利点は何ですか?

これは、値オブジェクトが不変であるべき理由に関する Martin Fowler による例です。

さて、VOを不変にすることは必須ではありませんが(DDDの本でさえ、不変である必要があるとは言っていません)、DDDでVOにする主なアイデアは、ライフサイクルの複雑さに対処することではないようですエンティティのそれ。詳しくはこちらをご覧ください

于 2011-01-03T02:04:43.523 に答える
0

値オブジェクトは不変である必要があります。

多くの場合、不変オブジェクトは確かに生活をシンプルにします。...そして、それらは並行プログラミングの方法をより安全でクリーンにし、より多くの情報を得ることができます

値オブジェクトが可変であると考えてみましょう。

class Name{
string firstName,middleName,lastName
....
setters/getters
}

あなたの元の名前が リチャード・トーマス・クックだったとしましょう

ここで、firstName (Martin へ) と lastName (Bond へ) のみを変更するとします。不変オブジェクトでない場合は、メソッドを使用して状態を 1 つずつ変更します。Martin Thomas Bondの最終的な名前の前に、その集約状態でMartin Thomas Cookという名前を持つ 可能性は決して受け入れられません (また、後でコードを見る人に間違った考えを与え、その後の設計で望ましくないドミノ効果につながります)。

可変値オブジェクトは、不変オブジェクトで自由に与えられる 1 つのトランザクションで与えられる変更に対して整合性制約を明示的に適用する必要があります。したがって、値オブジェクトを不変にすることは理にかなっています。

于 2016-11-03T14:52:56.360 に答える