Значения объектов в DDD - почему неизменяемые?

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

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

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


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


РЕДАКТИРОВАТЬ: Для ясности, я не спрашиваю о типах значений CLR (против ссылочных типов). Я спрашиваю о концепции DDD более высокого уровня объектов значения.

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

6 ответов

Игнорируйте все сумасшедшие ответы о поточно-ориентированных и т. Д., Которые не имеют никакого отношения к DDD (Я еще не видел потокобезопасного O/R mapper или другого 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, вы получите одинаковое поведение в обоих случаях, и вы все равно сможете повторно использовать ссылки на объекты для меньшего объема памяти при построении графов объектов.

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

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

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

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

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

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

для безопасного совместного использования объекта он должен быть неизменным: его нельзя изменить, кроме как путем полной замены. (Эванс р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 при создании. Если вы делаете это, то вы знаете, что это всегда верно.

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

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

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

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

Это было задано давно, но я решил дать ответ с примером, который я считаю простым и очень простым для запоминания. Кроме того, 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;
    }
}

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

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

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

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

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

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

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

Другие вопросы по тегам