DDD имеет дело с двумя доменами, выполняющими одинаковые действия.

Не совсем уверен, как подойти к этой проблеме в отношении DDD.

Допустим, у вас есть 2 домена:

  • Домен Product, который отвечает за создание новых и управление существующими доменами Products, созданными пользователем. Product Aggregate Root
  • Домен Store, который отвечает за назначение всех созданных Products данному Store для продажи и другие вещи. Но Store также может создавать новые Products, которые будут назначены им самим, но также доступны для других Stores, чтобы они могли назначить Product себе. Store Aggregate Root

Product может существовать без принадлежности к Store. Store может существовать без какого-либо Products (знаю, это не имеет смысла, но это всего лишь простой пример сложного решения, над которым я работаю в банкомате).

Поэтому, когда в систему входит Person, они могут начать с любого конца. Они могут начать с создания нового Products или с добавления нового Store.

Вот где все усложняется, когда они создают новый Store, им предоставляется возможность добавить существующий Products или они могут создать новый Product и добавить его к Store.

Как вы справляетесь с этим вариантом использования. есть ли у Store поведение по отношению к CreateNewProduct, где он отвечает за настройку нового Product и последующее добавление его в Store. Или вы просто создаете новый Product за пределами домена Store как часть домена Product и сообщаете Store AddProduct/AddExistingProduct?

ОБНОВЛЕНИЕ: подходит ли что-то подобное в качестве Domain Service

public class StoreProductService {

    public Store CreateNewStoreProduct (Store store, string sku, string name, etc){

        Product newProduct = ProductFactory.CreateNewProduct(sku, name, etc);

        store.AddProduct(newProduct);

        return store;
    }
}

person Shane van Wyk    schedule 07.03.2016    source источник
comment
Вам нужен третий домен, который должен действовать как шаблон фасада. Таким образом, задача этого третьего домена состоит в том, чтобы создать магазин или продукт или связать их вместе. А шаблон фасада поможет вам скрыть сложность системы, предоставив более простой интерфейс для доступа к продукту и домену магазина,   -  person adeel41    schedule 08.03.2016
comment
Я здесь с Адель; вам нужна третья концепция - ProductFactory или что-то подобное. Продукты не создают сами себя, а Магазины не создают Продукты — они просто содержат их.   -  person Stephen Byrne    schedule 08.03.2016
comment
Да, у меня есть ProductFactory, который создает для меня новый продукт. Но вы тогда позволите Store AddProduct(product) или CreateNewProduct (артикул, имя и т. д.) . Which means that the Store` Сущность должна будет знать о ProductFactory. Таким образом, очевидно, что у вас будет Store служба приложений, которая занимается добавлением нового продукта. Итак, в этом методе создания вы используете ProductFactory и передаете его в хранилище после его создания?   -  person Shane van Wyk    schedule 08.03.2016
comment
@StephenByrne - см. комментарий выше   -  person Shane van Wyk    schedule 08.03.2016
comment
Вы путаете домен с агрегатом?   -  person VoiceOfUnreason    schedule 08.03.2016
comment
@VoiceOfUnreason - Наверное, я новичок в DDD. Я бы сказал, что Store и Product — это 2 совокупных корня, потому что они могут существовать сами по себе. Но не уверен, что совокупный корень может взаимодействовать с другим без промежуточного класса/объекта/службы. В идеале я хотел бы получить ответ с примером хорошего подхода для этого.   -  person Shane van Wyk    schedule 08.03.2016
comment
Общее эмпирическое правило заключается в том, что если агрегату требуется другой агрегат для взаимодействия, это выполняется через доменную службу. Дочерние объекты в дереве объектов каждого агрегата никогда не должны изменяться напрямую. Любая модификация агрегата должна проходить через корневой объект агрегата.   -  person Adrian Thompson Phillips    schedule 08.03.2016
comment
@AdrianThompsonPhillips, пожалуйста, посмотрите обновленный вопрос, будет ли это подходящим подходом к этой проблеме?   -  person Shane van Wyk    schedule 08.03.2016
comment
Может быть, что-то вроде StoreProductService.CarryProductInStore(myProduct, myStore). Это использует язык домена и позволяет настраивать продукты до того, как они будут назначены какому-либо магазину.   -  person Adrian Thompson Phillips    schedule 08.03.2016
comment
ОБНОВЛЕНИЕ: нет, это неправильное направление.   -  person VoiceOfUnreason    schedule 08.03.2016
comment
@ShaneVanWyk, вы до сих пор не уточнили, являются ли Product и Store двумя поддоменами, то есть большими функциональными областями, которые могут развиваться отдельно, каждая со своими бизнес-командами и, возможно, командами разработчиков, или двумя агрегатами< /i> внутри одного поддомена.   -  person guillaume31    schedule 09.03.2016
comment
@ guillaume31 - Ну, они могут развиваться отдельно, поэтому, пока я работаю в магазине, другой разработчик может работать над продуктом. Бизнес-правила заключаются в том, что можно создать магазин, этот магазин может просто иметь имя и быть пустым. Это будет бесполезный магазин, но это нормально, эксперт в предметной области так хочет. Тем не менее, в магазине могут быть товары/услуги, я поместил услуги здесь, чтобы сделать его более простым. Магазин может выбрать добавление из существующего каталога или создать свой собственный, но когда они создают свой собственный, его также необходимо добавить в каталог, чтобы другие магазины могли его использовать.   -  person Shane van Wyk    schedule 11.03.2016


Ответы (2)


Вам нужны два домена для связи друг с другом. Вы можете общаться, используя различные методы, но одним из распространенных способов является использование REST API. В вашем домене Магазина вам нужно что-то, что общается или знает, как общаться с API. Обычно я реализовывал их как службу, которая оборачивает вызовы API. Сервис сможет понимать ваш домен Ubiquitous language и переводит его в команды API. Вы можете использовать события домена, чтобы, возможно, прослушивать, когда продукт был создан, а затем вы можете связать магазин с продуктом или реализовать какой-либо механизм опроса.

Был запрошен пример, так что вот:

Вызов из пользовательского интерфейса (вероятно, из контроллера)

StoreService.CreateStore(storeName: String, newProduct : StoreProduct) Вы можете передать примитивы для представления нового продукта. Это позволяет создавать новый продукт без необходимости создания для него нового класса. Впоследствии вам не понадобится класс общей инфраструктуры или преобразователь между вашим доменом и слоями пользовательского интерфейса.

StoreService

public StoreService
{
      public StoreService(ProductApiClient productApiClient...)...
      public void CreateStore(string StoreName, StoreProduct prod...)
      {
             var newStore = StoreFactory.Create(storeName);
             //below might be better as an asynch call but for simplicity
             //keeping it all synchronous
             var newProd = productApiClient.CreateProduct(prod);
             //check if product was created successfully, if so
             newStore.Add(newProd);
             //save
             StoreRepo.Create(newStore);
             //check if store was created successfully
       }

Основные моменты, которые нужно взять отсюда:

  1. Создайте свою совокупную сущность с помощью фабрики (в этом состоянии она не сохраняется).
  2. Вам нужно репо для сериализации и сохранения вашего нового хранилища в вашем хранилище данных.
  3. productApiClient будет переводить между вашей моделью домена и запросом к productApi. Он знает, как генерировать запрос API (например, REST) ​​для заданных объектов домена.
  4. ProductApiClient вернет объект домена из ответа API.
  5. Вы добавляете новый продукт в магазин, используя сущность магазина.
  6. Вы сохраняете свой магазин, используя репо
  7. Вы можете выбрать более асинхронный подход, если вызов API занимает много времени.

Этот пример иллюстрирует мощь DDD и разделение ответственности. В зависимости от размера вашего проекта и ваших требований, это может быть слишком утомительно, поэтому приспосабливайте его к вашим потребностям, навыкам и требованиям.

person Louis    schedule 08.03.2016
comment
Не лучше ли иметь прикладные сервисы? Так, например, у вас есть StoreService, который является службой приложений, и он знает о ProductFactory. Таким образом, из вашего слоя пользовательского интерфейса вы вызовете StoreService CreateNewrProduct, затем это вызовет ProductFactory CreateProduct. Результат этого будет возвращен в магазин для добавления недавно добавленного продукта. - person Shane van Wyk; 11.03.2016
comment
Затем вы объединяете два домена или допускаете утечку логики. Служба Store не должна ничего знать о продуктах, кроме того, что домен продуктов предоставляет в своем API. Уровень вашего пользовательского интерфейса должен вызывать CreateNewStore (при взаимодействии с доменом магазина) и передавать достаточно информации туда, где служба приложения может создать новый продукт, если это необходимо (используя API-интерфейс, предоставляемый доменом продукта). Помните, что вам может потребоваться выполнить такие действия, как проверка доступности или некоторые другие действия, связанные с продуктом. Вот почему вам необходимо достаточно изолировать, чтобы домен вашего магазина не должен был знать об этих вещах. - person Louis; 12.03.2016
comment
Это имеет смысл. Можете ли вы обновить свой ответ гипертетическим примером? - person Shane van Wyk; 12.03.2016

Эта бизнес-проблема очень распространена. Вы наверняка можете найти несколько примеров систем электронной коммерции с DDD.

Типичная ситуация: вы не закончили разработку UL. Если вы обсуждаете Магазин (я не буду отмечать его как код, поскольку я говорю о терминах UL, а не о классах) со специалистами в своей области, вы можете обнаружить, что Магазин заботится только о Доступности Продукта, а не о самом Продукте.

Как правило, ваш Продукт, входящий в Каталог продуктов, не имеет ничего общего с доступностью. Он может содержать общее описание, сведения о производителе, стране происхождения, изображении, размере и весе упаковки и так далее.

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

Дело в том, что зачастую оба этих понятия, несмотря на то, что они довольно разные, специалисты предметной области относят к «Продукту». Это типичный пример двух отдельных ограниченных контекстов.

Как только у вас появятся две разные вещи под названием Product в двух разных Bounded Contexts (и физических местах), вам нужно будет синхронизировать их. Обычно это делается путем публикации событий домена за пределами ограниченного контекста и обновления другой стороны путем подписки на эти события там и выполнения внутренней обработки команд домена внутри ограниченного контекста.

person Alexey Zimarev    schedule 08.03.2016
comment
Пробовал искать Решения для электронной коммерции, не могу найти пример, в котором также участвует магазин. Такой пример мне бы очень помог. Однако, даже если это может выглядеть как решение для электронной коммерции, это не так. Я заменил настоящие домены товаром и магазином, потому что это достаточно близко и имеет ту же логику, что и то, что мы пытаемся сделать. Я не могу привести реальный пример, так как он защищен I.P. - person Shane van Wyk; 11.03.2016
comment
Проблема здесь в том, что каждый дизайн очень специфичен для фактической области. Практически невозможно дать конкретный совет по проектированию, не зная предметной области и не создавая UL и BC. По сути, как говорит Вернон, DDD разрабатывает вездесущий язык внутри ограниченного контекста. В вашем случае, поскольку все это секретно, боюсь, вы сами по себе... пример электронной коммерции с отображением контекста можно найти в книге IDDD. - person Alexey Zimarev; 11.03.2016