Объекты значения — базовый элемент организации логики

Объекты значения — базовый элемент организации логики

В предыдущих постах мы разобрали подходы к организации бизнес-логики — Transactional Script, Active Record. Теперь начнем движение в сторону полноценной Domain Model. Но сначала хочется подробнее остановиться на одном из фундаментальных строительных блоков доменной модели — Value Object. Этот паттерн прост по своей сути, но вместе с тем очень часто его неправильно имплементируют или используют.

Концепция Value Object сформировалась в ООП задолго до появления DDD. Еще Мартин Фаулер описывал паттерн для работы с небольшими неизменяемыми объектами. Но как основа и важный строительный блок разработки сложных программных систем была представлена в знаменитой «Синей Книге» Эрика Эванса — Domain-Driven Design: Tackling Complexity in the Heart of Software (2003).

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

Например, адрес доставки, денежная сумма, цвет товара — это все значения, а не сущности. Объекты с одинаковыми свойствами взаимозаменимы.

Свойства Value Objects

У Value Object есть определенный набор строгих характеристик:

🔹 Иммутабельность — после создания объект не должен менять свое внутреннее состояние. Любое изменение создает новый объект.

🔹 Отсутствие идентичности — Value Object полностью определяется своими атрибутами. Два объекта равны, если равны их атрибуты.

🔹 Инвариантность — содержит всю необходимую логику для работы со своими атрибутами: валидация, вычисления, преобразования.

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

В чем отличие от Domain Entity

Самый частый вопрос при проектировании — как понять, что перед вами Value Object, а не Domain Entity?

Ключевое отличие заключается в наличии идентичности (Identity) и жизненного цикла.

  • Domain Entity имеет уникальный идентификатор (ID). Сущность проживает определенный жизненный цикл: она создается, меняет свои состояния с течением времени и удаляется. Нам критически важно отличать одну сущность от другой, даже если у них совпадают атрибуты.
  • Value Object не имеет идентификатора. У него нет истории изменений. Это просто слепок данных в конкретный момент времени.

Правило большого пальца: Всегда старайтесь моделировать концепцию как Value Object. Переходите к Entity только тогда, когда абсолютно необходимо отслеживать жизненный цикл этого объекта и отличать его от других таких же по уникальному ключу.

Как реализовывать Value Objects

Основные нюансы реализации Value Object:

✅ Делайте Value Objects иммутабельными.

✅ Переопределяйте equals(), hashCode() (если пишете на Java).

✅ Валидацию производите в конструкторе или выносите в фабричный метод.

✅ Избегайте прямых модификаций полей (не используйте setXxx(...)) — используйте withXxx() для создания новых экземпляров.

Пример реализации на Java с использованием Record:

// Использование record дает нам Immutability, equals и hashCode из коробки public static record Money(BigDecimal amount, String currency) { // Самовалидация в конструкторе record public Money { if (amount == null || amount.compareTo(BigDecimal.ZERO) < 0) { throw new IllegalArgumentException("Сумма не может быть отрицательной"); } if (currency == null || currency.isBlank()) { throw new IllegalArgumentException("Валюта должна быть указана"); } } // Метод без побочных эффектов: возвращает новый объект public Money add(Money other) { if (!this.currency.equals(other.currency())) { throw new IllegalArgumentException("Нельзя складывать разные валюты"); } return new Money(this.amount.add(other.amount()), this.currency); } }

Выводы

  • Value Objects — это основные строительные блоки доменной модели.
  • Value Objects обладают собственным поведением и инвариантами.
  • Они помогают повысить безопасность и выразительность кода.

Не бойтесь создавать много маленьких объектов значений — это инвестиция в читаемость, выразительность и надёжность вашей системы.

Подпишись на мой канал в telegram

Начать дискуссию