PHP Profi

DDD в PHP: Value Object или Объект-Значение Перевод

php value object DDD

Определение Мартина Фаулера:

Небольшой простой объект, как деньги или диапазон дат, равенство которых не основано на идентичности

Объект-Значение (Value Object) — это объект, который представляет собой понятие из предметной области. В DDD (Domain Driven Development — разработка на основе предметной области, или предметно-ориентированное программирование) важно то, что Value Object поддерживает и обогащает Единый Язык вашей Предметной Области. Это не только примитивы, которые представляют собой некоторые значения, — они являются полноправными гражданами Предметной Области, которые формируют поведение вашего приложения.

Хорошие примеры Value Object-ов, упомянутые у Мартина, — деньги и время. При создании ГИС-приложений вы можете прийти к такому Объекту-Значению, как  Location($lat, $long), который будет инкапсулировать широту/долготу и подобное. Вопрос, который вы, вероятно, захотите задать — почему это лучше, чем просто передать два float`а в массиве и называть это $location?

Преимущества использования Value Objects

Самое главное заключается в том, что эти объекты отражают язык, на котором вы разговариваете с другими разработчиками — когда вы говорите «Место»(Location) все знают, что это значит. Второе преимущество заключается в том, что Value Object может валидировать значение — подходит оно или нет для того, чтобы создать такой объект.

Третьим преимуществом является то, что вы можете полагаться на тип — вы знаете, что если такой 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);
    }
}

Вышеприведённая реализация:

  • обеспечивает, что Объект-Значение EmailAddress всегда находится в допустимом состоянии;
  • позволяет использовать подсказки типов (тайп-хинтинг) и убрать проверки email-ов (впоследствии упростить логику приложения);
  • предоставляет возможность приведения к строке;
  • предоставляет метод для сравнения его с другими EmailAddress.

Одержимость примитивами

Вы можете неохотно относиться к использованию объектов в качестве контейнеров для примитивных значений, но подобные вещи описаны как "код с запашком" под названием «Одержимость примитивами»:

Одержимость примитивами — это использование примитивных типов данных для представления сущностей Предметной области. Например, мы используем String для представления сообщения, Integer в качестве суммы денег, или Struct/Dictionary/Hash для представления конкретного объекта.

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

Неизменяемость

Очень важно помнить и понимать, что Value Object является неизменяемым. Почему это такое важное понятие? Задумайтесь о реальности вокруг вас и какие значения вы используете — число один, красный цвет и так далее. Вы не можете изменить эти значения — это не имеет смысла, менять красный цвет на зеленый, и продолжать называть его красным — это больше не красный, и называние зеленого красным будет путать людей. Таким же образом Value Object в вашем приложении должны быть неизменными.

Например, у вас есть сущность «Собрание» в вашей Предметной Области, и у этого Собрания есть некоторая Дата (Value Object). Теперь дата встречи изменилась, но не сама дата - 22 марта все еще 22 марта. Это собрание, которое требует назначения новой даты, а не изменения самой даты, поэтому выкиньте старую дату и создайте новую.

Резюме

Value Object-ы являются важными гражданами вашей Предметной Области, которые отражают его концепции. Убедитесь, что вы приложите соответствующее поведение к таким объектам, которое впоследствии будет делать код более организованным и лучше передавать реальность, потому что ключевым аспектом и целью объектно-ориентированного программирования является моделирование реального мира.

2017-04-16 alek13 Поделиться: оригинал