Квест → Как хакнуть форму
Прошли: 77
Небольшой простой объект, как деньги или диапазон дат, равенство которых не основано на идентичности
Объект-Значение (Value Object) — это объект, который представляет собой понятие из предметной области. В DDD (Domain Driven Development — разработка на основе предметной области, или предметно-ориентированное программирование) важно то, что Value Object поддерживает и обогащает Единый Язык вашей Предметной Области. Это не только примитивы, которые представляют собой некоторые значения, — они являются полноправными гражданами Предметной Области, которые формируют поведение вашего приложения.
Хорошие примеры Value Object-ов, упомянутые у Мартина, — деньги и время. При создании ГИС-приложений вы можете прийти к такому Объекту-Значению, как Location($lat, $long)
, который будет инкапсулировать широту/долготу и подобное. Вопрос, который вы, вероятно, захотите задать — почему это лучше, чем просто передать два float`а в массиве и называть это $location
?
Самое главное заключается в том, что эти объекты отражают язык, на котором вы разговариваете с другими разработчиками — когда вы говорите «Место»(Location) все знают, что это значит. Второе преимущество заключается в том, что Value Object может валидировать значение — подходит оно или нет для того, чтобы создать такой объект.
Третьим преимуществом является то, что вы можете полагаться на тип — вы знаете, что если такой Value Object был принят в качестве аргумента, он будет всегда в допустимом состоянии и вам не нужно беспокоиться об этом. И также Value Object может содержать некоторые специализированные методы, которые имеют смысл только в контексте этого значения и могут быть расположены в этом объекте (не нужно создавать странные классы-утилиты).
В качестве примера Value Object-а, который является распространённым для всех веб-приложений, я создал EmailAddress:
class EmailAddress { private $address; public function __construct($address) { if (!filter_var($address, FILTER_VALIDATE_EMAIL)) { throw new InvalidArgumentException(sprintf('"%s" is not a valid email', $address)); } $this->address = $address; } public function __toString() { return $this->address; } public function equals(EmailAddress $address) { return strtolower((string) $this) === strtolower((string) $address); } }
Вышеприведённая реализация:
Вы можете неохотно относиться к использованию объектов в качестве контейнеров для примитивных значений, но подобные вещи описаны как "код с запашком" под названием «Одержимость примитивами»:
Одержимость примитивами — это использование примитивных типов данных для представления сущностей Предметной области. Например, мы используем String для представления сообщения, Integer в качестве суммы денег, или Struct/Dictionary/Hash для представления конкретного объекта.
Использование Value Object-ов является одной из стратегий борьбы с этим запахом. Ключевая идея здесь — это собрать поведение данных вокруг своего объекта. В противном случае такие действия будут разбросаны по всему коду, что может привести к ненужной сложности и заставит вас относиться с опаской к значениям, переданным в методы.
Очень важно помнить и понимать, что Value Object является неизменяемым. Почему это такое важное понятие? Задумайтесь о реальности вокруг вас и какие значения вы используете — число один, красный цвет и так далее. Вы не можете изменить эти значения — это не имеет смысла, менять красный цвет на зеленый, и продолжать называть его красным — это больше не красный, и называние зеленого красным будет путать людей. Таким же образом Value Object в вашем приложении должны быть неизменными.
Например, у вас есть сущность «Собрание» в вашей Предметной Области, и у этого Собрания есть некоторая Дата (Value Object). Теперь дата встречи изменилась, но не сама дата - 22 марта все еще 22 марта. Это собрание, которое требует назначения новой даты, а не изменения самой даты, поэтому выкиньте старую дату и создайте новую.
Value Object-ы являются важными гражданами вашей Предметной Области, которые отражают его концепции. Убедитесь, что вы приложите соответствующее поведение к таким объектам, которое впоследствии будет делать код более организованным и лучше передавать реальность, потому что ключевым аспектом и целью объектно-ориентированного программирования является моделирование реального мира.