Значения объектов в DDD - Почему неизменяемы? - PullRequest
33 голосов
/ 03 января 2011

Я не понимаю, почему объекты-значения в DDD должны быть неизменяемыми, и я не вижу, как это легко сделать. (Я концентрируюсь на C # и Entity Framework, если это имеет значение.)

Например, давайте рассмотрим классический объект значения адреса. Если вам нужно изменить «123 Main St» на «123 Main Street », зачем мне нужно создавать целый новый объект вместо того, чтобы говорить myCustomer.Address.AddressLine1 = "123 Главная улица"? (Даже если Entity Framework поддерживает структуры, это все равно будет проблемой, не так ли?)

Я понимаю (я думаю) идею, что объекты-ценности не имеют идентичности и являются частью объекта домена, но может ли кто-нибудь объяснить, почему неизменность - это хорошо?


РЕДАКТИРОВАТЬ : мой последний вопрос здесь действительно должен звучать так: «Может ли кто-нибудь объяснить, почему неизменность является хорошей вещью применительно к объектам значений ?» Извините за путаницу!


EDIT : Для ясности, я не спрашиваю о типах значений CLR (против ссылочных типов). Я спрашиваю о концепции DDD более высокого уровня объектов значения.

Например, вот хакерский способ реализации неизменяемых типов значений для Entity Framework: http://rogeralsing.com/2009/05/21/entity-framework-4-immutable-value-objects. По сути, он просто делает все установщики закрытыми. Зачем делать это?

Ответы [ 6 ]

42 голосов
/ 03 января 2011

Игнорировать все сумасшедшие ответы о поточно-ориентированных и т. Д., Которые не имеют никакого отношения к DDD. (Я еще не видел потокобезопасного маппера O / R или другого dal-дружественного dal)

Представьте себе объект значения для весов. скажем, у нас есть объект значения KG.

образец (отредактированный для ясности):

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

Теперь, что произойдет, если мы сделаем:

jimmy.Weight.Value = 82;

Это также изменило бы вес Джо, если бы мы все еще использовали те же ссылки на объекты, что и. Обратите внимание, что мы присвоили объект, представляющий 75 кг, как Джо, так и Джимми. Когда Джимми набирает вес, изменился не объект kg75, а вес Джимми, поэтому мы должны создать новый объект, представляющий 82 кг.

Но что, если у нас будет новый сеанс и мы загрузим Джо и Джимми в чистую 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 в вашем случае будет загружать Джо и Джимми и их веса без какой-либо идентичности, мы получим два разных объекта веса, и когда мы изменим вес Джиммиса, Джо все равно будет весить так же, как и раньше.

Таким образом, у нас было бы два разных поведения для одного и того же кода. Если ссылки на объекты остаются прежними, то и Джо, и Джимми получили бы новый вес. Если Джо и Джимми загружены в чистом виде, изменения коснутся только одного из них.

И это было бы совершенно бесцеремонным ИМО.

Используя неизменяемые VO, вы получите одинаковое поведение в обоих случаях, и вы все равно сможете повторно использовать ссылки на объекты для меньшего объема памяти при построении графов объектов.

33 голосов
/ 03 января 2011

Почему 6 неизменным?

Поймите это, и вы поймете, почему объекты-значения должны быть неизменными.

Редактировать: я подниму наш диалог в этот ответ сейчас.

6 является неизменным, потому что идентичность 6 определяется тем, что он представляет, а именно состоянием наличия шести чего-либо. Вы не можете изменить, что 6 представляет это. Теперь, это фундаментальная концепция объектов значения. Их ценность определяется их состоянием. Однако сущность не определяется своим состоянием. Customer может изменить свою фамилию или адрес и при этом остаться прежним Customer. Вот почему Value Objects должны быть неизменными. Их состояние определяет их личность; если их состояния меняются, их личность должна меняться.

10 голосов
/ 08 февраля 2011

Я очень опоздал на вечеринку, но мне самому было интересно. (Буду признателен за любые комментарии.)

Я не думаю, что это было явно процитировано здесь, но я думаю, что ссылки Эванса на неизменность были в основном в контексте обмена:

для безопасного совместного использования объекта , он должен быть неизменным: он не может быть изменено, кроме как полной заменой. (Эванс р100)

В книге Эвана также есть боковая панель «Является ли адрес ценным объектом? Кто спрашивает?».

Если соседи по комнате звонят, чтобы заказать электрическое обслуживание [то есть, если два клиента имеют один и тот же адрес], компания будет нужно осознать это. [Итак] Адрес - это сущность. (Эванс, стр. 98)

В приведенном вами примере предположим, что домашний и рабочий адрес клиента были 123 Main Street. Когда вы сделаете исправление, которое вы описываете, изменится ли оба адреса? Если это так, и если я правильно читаю Эванса, похоже, у вас действительно есть сущность.

Взяв другой пример, предположим, что у нас был объект, представляющий полное имя клиента:

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 при создании. Если вы это сделаете, то знаете, что это всегда верно.

5 голосов
/ 03 января 2011

Это может быть не полный ответ. Я только отвечаю на ваш вопрос о преимуществах неизменности.

  1. Поскольку неизменяемые объекты являются нитями безопасный. Так как они не могут измениться государство, они не могут быть испорчены интерференция потока или наблюдается в противоречивое состояние.
  2. Ссылки на неизменное объекты могут быть легко разделены или кэшируется без копирования или клонировать их как их состояние нельзя изменилось после строительства.
  3. Для большего преимущества неизменности вы смотрите здесь (ответ Л.Бушкина) В чем преимущество неизменности String?

Это пример Мартина Фаулера о том, почему объекты-значения должны быть неизменными.

Хорошо, хотя необязательно делать VO неизменяемым (даже в DDD не говорится, что они должны быть неизменяемыми), главная идея в DDD сделать это VO, похоже, не связана с жизнью сложность цикла, как у сущности. Смотрите здесь для более подробной информации .

0 голосов
/ 02 августа 2018

Это было задано давно, но я решил дать ответ с примером, который я считаю простым и очень простым для запоминания.Кроме того, SO работает как справка для многих разработчиков, и я думаю, что любой, кто сталкивается с этим вопросом, мог бы извлечь из этого пользу.

Поскольку они определяются своими атрибутами, объекты значений рассматриваются как неизменяемые ,

Хорошим примером ценностного объекта являются деньги.Неважно, что вы не можете различить те же пять однодолларовых банкнот в вашем кармане.Вам не важна идентичность валюты - только ее ценность и то, что она представляет.Если кто-то поменяет пятидолларовую купюру на ту, которая у вас есть в кошельке, это не изменит того факта, что у вас все еще есть пять долларов.

Так, например, в C # вы определяете деньги как объект неизменной стоимости:

public class Money
{
    protected readonly decimal Value;

    public Money(decimal value)
    {
        Value = value;
    }

    public Money Add(Money money)
    {
        return new Money(Value + money.Value);
    }

    // ...


    // Equality (operators, Equals etc) overrides (here or in a Value Object Base class). 
    // For example:

    public override bool Equals(object obj)
    {
        return Equals(obj as Money);
    }

    public bool Equals(Money money)
    {
        if (money == null) return false;
        return money.Value == Value;
    }
}
0 голосов
/ 03 ноября 2016

Значимые объекты должны быть неизменными.

Неизменяемые объекты действительно упрощают жизнь во многих случаях.... И они могут сделать параллельное программирование более безопасным и чистым для получения дополнительной информации

Давайте рассмотрим объект значения как изменяемый.

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

Допустим,Ваше первоначальное имя было Ричард Томас Кук

Теперь предположим, что вы меняете только firstName (на Martin) и lastName (на Bond). Если это не неизменяемый объект, вы будете использовать методымутировать состояние по одному.Вероятность иметь имя как Мартин Томас Повар в этом Сводном состоянии перед окончательным именем Мартин Томас Бонд никогда не приемлема (также это дает неверное представлениетот, кто смотрит код позже, что приводит к нежелательному эффекту домино в дальнейшем дизайне).

Объекты с изменяемым значением явно должны обеспечивать ограничения целостности для изменений, указанных в 1 транзакции, которая предоставляется бесплатно в неизменяемых объектах.Следовательно, имеет смысл сделать объекты значения неизменяемыми.

...