2011-02-02 3 views
32

Предположим, у нас есть архитектура, основанная на CQRS, с такими компонентами, как команды, модель домена, события домена, чтение моделей DTO.
Конечно, мы можем использовать объекты Value в нашей модели домена. Мой вопрос, они должны также быть использованы в:Объекты Value в CQRS - где использовать

  1. Команды
  2. События
  3. DTOs

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

Мотивация:

Команды.
Предположим, что пользователь отправил форму, содержащую поля адреса. У нас есть объект Address Value для представления этой концепции. При построении команды в клиенте мы должны все равно проверять ввод пользователя, и когда он хорошо сформирован, мы можем создать объект Address прямо там и инициализировать команду с ним. Я не вижу необходимости делегировать создание объекта Address в обработчик команд.

События домена.
Доменная модель уже работает с точки зрения объектов-объектов, поэтому, публикуя события с VO вместо их преобразования в примитивные типы, мы можем избежать некоторого кода сопоставления. Я почти уверен, что в этом случае использовать VO.

DTOs.
Если наши DTO на стороне запроса могут содержать объекты Value, это обеспечивает некоторую гибкость. Например, если у нас есть объект Money, мы можем выбрать, показывать ли его в EUR или USD, не нужно изменять Read Model.

+3

Подумав об этом некоторое время, мой вывод: наличие объектов с активным поведением в Events просто невозможно, поскольку они должны представлять исторические данные, и сегодня у нас нет возможности сериализовать поведение. Что касается Commands и Read Model DTO, это может сработать, и мне все еще неясно, подходит ли оно, связанное с ним, или нет (во всяком случае, это больше о том, должны ли оба слоя домена и представления ссылаться на ту же реализацию Money VO ' а не «должен TransferMoneyCommand содержать Money VO или MoneyDTO»). – driushkin

ответ

22

Хорошо, я передумал. В последнее время я пытаюсь разобраться с VOs, и после просмотра этого http://www.infoq.com/presentations/Value-Objects-Dan-Bergh-Johnsson он разъяснил мне пару вещей.

Команды и события - это сообщения (а не объекты, объекты - данные + поведение), в некотором отношении очень похожие на DTO, они обмениваются данными о событии и сами не инкапсулируют никакое поведение.

Объекты Value не похожи на DTO. Они представляют собой представление домена, и они, вообще говоря, богаты поведением, как и все остальные представления домена.

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

Чтобы перефразировать Орен (хотя он имел в виду nHibernate и WCF) «Не отправляйте свой домен через провод». http://ayende.com/Blog/archive/2009/05/14/the-stripper-pattern.aspx

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

Исходный текст (для потомков):

Если вы спрашиваете, если значение Объекты могут быть переданы с помощью модели предметной области к событиям или передается в командами, я действительно не вижу огромную проблему с прежним, хотя последнее может нарушать некоторые из правил совокупного корня, являющегося «владельцем» значений.

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

Чтение главы из DDD по шаблону Aggregate Root объясняет объекты и объекты Value довольно хорошо и стоит прочитать несколько раз.

+0

Я думаю, что это нормально с чистой DDD-перспективы для совместного использования VO, но с точки зрения cqrs это может привести к некоторым техническим проблемам, таким как управление версиями событий, если применяется Event Sourcing. И тогда возникает естественный вопрос, действительно ли это только техническая проблема, или это что-то внутренне не соответствует всей идее. – driushkin

+0

Понимание, которое я взял из книги DDD, состоит в том, что, хотя совокупные корни являются владельцами их соответствующих объектов и объектов значений, они могут временно передавать ссылку на эти объекты. Единственной целью совокупного корня является определение транзакционных границ системы. Опять же, я могу неправильно истолковать некоторые из них и, как всегда, YMMV. Хотя, конечно, было бы плохо сериализовать сущность как часть события. Я не вижу никаких проблем для VO, поскольку они должны представлять истинное неизменяемое значение. –

+5

«Объекты значения вообще не похожи на DTO. Они представляют собой представление домена, и они [...] богаты поведением, как и все другие представления домена». Я бы не согласился с последней частью. Хотя они являются частью домена (например, определяют, что такое * Адрес *), они должны быть одноразовыми и не иметь никакого поведения, связанного с ними. Вот почему они обычно неизменны, чтобы вы не захотели возиться со своим VO. – Dav

4

Я говорю, что это плохая идея.

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

Представьте, что вы делаете событие, содержащее VO. Изменение вашего домена требует от вас изменения этого VO. Теперь вы убрали себя в угол, где ваше событие также вынуждено изменить, то же самое для любых команд или DTO, это часть.

Этого следует избегать.

Используйте DTO и/или примитивы. Сопоставьте их (AutoMapper делает сделку с 1 строкой).

+1

Ну, эти ВО не будут принадлежать исключительно доменной модели. Они будут общим знанием для всех компонентов системы (например, сборка MyApp.Core, на которую может ссылаться любой). Пока концепции там стабильны или даже не имеют никаких изменений, я думаю, это должно быть хорошо. Ofc, если мы используем Event Sourcing, это загромождает наш код устаревшими концепциями, которые больше не используются, но являются частью старых событий. Так что это один из недостатков, о котором я могу думать. Но, тем не менее, идея создания модуля общих понятий (например, Currency, Money, Velocity) во всем приложении звучит так соблазнительно для меня. – driushkin

+0

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

+0

Я также чувствую, что VO в CQRS - плохая идея, но тогда как мы можем инкапсулировать логику домена, когда агрегат станет сложным? –

3

Как и в других ответах, в SOA это нарушит инкапсуляцию службы, поскольку домен теперь протекает.

0

В соответствии с Clean Code ваши DTO являются структурами данных (просто для добавления другого термина), а объекты значений - объекты. Разница в том, что объекты могут иметь поведение. Смешивание структур данных с объектами, как правило, очень плохое, потому что будет сложно поддерживать гибрид, который вы получаете.

Я не считаю, что объекты DTO также могут быть добавлены к объектам архитектуры. Объекты значения находятся внутри модели домена, а упомянутые вами DTO определяют интерфейс модели. Обычно мы создаем интерфейс, чтобы отделить внешний мир от чего-то. Таким образом, в текущем случае мы добавили DTO, чтобы отделить внешний мир от объектов ценности (и других связанных с моделью материалов). После этого добавление объектов значения в интерфейс сходит с ума.

Итак, вы еще не встретили это решение, потому что это анти-шаблон.

+0

Так что мы не должны добавлять никаких типов String или Integer в DTO, так как это также объект значения? – bojanv55

+0

@ bojanv55 Строки и целые числа - это примитивы, а не значения объектов. Объект Date или DateTime был бы лучшим примером. Я имел в виду, что DTO не должны передавать VO, определенные в домене. Например, у нас есть VO в нашем домене, связанный с рождением кого-то, например. 1985-12-20. Если мы запросим день рождения, тогда мы должны вернуть 12-20 в DTO. Если мы запросим дату рождения, тогда мы должны вернуть 1985-12-20 в DTO. Если мы запросим возраст, тогда мы должны вернуть 31 год в DTO. Таким образом, DTO не будет содержать весь VO с его логикой, просто представление, которое нам действительно нужно. – inf3rno

+0

@ bojanv55 По крайней мере, так я использую DTO и VO. Этот подход сработал до сих пор, но с. Я не безошибочен. :-) – inf3rno

Смежные вопросы