DDD и MVC: Contoller получает AggregateRoot из Factory not Repository? а?


Я недавно начал работать над проектом с существующей базой данных (Oracle) и MVC 4. Много кодирования уже произошло.. но в кодексе нет никакой" стратегии".. просто DB - > ORM - > контроллер. Так что я пытаюсь добавить некоторую вспышку в разработку, а также практиковать некоторые методы разработки DDD.

Я определил пару агрегатных корней, каждый из которых имеет хранилище, которое занимается их сохранением и удалением (и их потомков)и т. д.. один из этих агрегатных корней имеет отношение к другому Агрегатный корень, и он имеет дело с его" дочерними объектами " через него.

Пример:

A Client has one or more purchase orders which has Line Items, 
if a client wants to add a line item to the purchase order, 
it has to go through the purchase order.

Это прекрасно.. агрегатный корень клиента, агрегатный корень заказа на покупку.

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

В настоящее время репозитории выполняют свою работу по сохранению данных из базы данных и "заполняют" AR данными. когда AR "сохраняет" его, хранилище, сохраняет все, что нуждается в сохранении. Репозиторий заказов на покупку используется клиентом AR таким образом, клиент может загружать любые заказы на покупку, которые он может содержать.. Надеюсь, я на правильном пути.

Теперь введите MVC. Так что у меня тоже есть немного ViewModels, которые в основном отображают определения того, что должно быть откачано пользователю. Automapper оказался чертовски удивительным, поэтому я могу просто "автоматически сопоставить" модель представления. Мозги не нужны, отлично..

Теперь детали реализации, которые действительно сбивают меня с толку..

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

Так что теперь я хочу убедиться, что это правильно.. потому что во многих примерах, которые я вижу, контроллеры работают с репозиториями, а не с фабриками, но я также видел, что фабрики рекомендуются для создания AR.. что приводит меня к мысли, что в примерах контроллеры имеют дело с агрегатными корнями, но таким образом, что это требует, чтобы" потребитель " запросил AR чтобы получить AR:

Как:

Get the Client Aggregate where the ClientID is 15

Или еще лучше:

get the Client Aggregate, where the ClientID is 15 
and where active purchase orders > 0 ...or something..

Который может выглядеть следующим образом:

ClientAR = ClientRepository.GetClientByIDAndHasActivePurchaseOrders(15);
resultsImLookingFor = ClientAR.PurchaseOrders(); //or something

Я чувствую, что в этом случае хранилище "наполнило" бы ClientAR для моих нужд, поэтому теперь у меня есть эта вещь ClientAR, которая варьируется в зависимости от ее использования, она пахнет для меня..

Использование фабрики "чувствует себя лучше", потому что я просто создаю клиентуру с фабрики, а затем использую ее, она не меняется в зависимости от ситуации.. это что такое это..

ClientAR  = ClientFactory.CreateClient(15) // returns a ClientAR 
resultsImLookingFor = ClientAR.GetPurchaseOrdersByStatus(statusID);

Или, может быть, я полностью упускаю это, и я должен делать это::

ClientAR = ClientRepository.GetClientByID(15, PurchaseOrderSpec)

Не упускаю ли я из виду спецификационную сторону вещей? (На данный момент у меня нет достаточно, чтобы действительно начать работать со спецификациями (просто пока), потому что мне нужно заставить эти вещи работать)

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

Итак, правильно ли я подхожу к этому? если это можно оспорить, я не возражаю.. если это просто неправильно, то руководство определенно ценится, и если я далек от этого, конструктивная критика не заденет мои чувства, если за этим стоит хорошая причина..

Заранее благодарю.

1 2

1 ответ:

Таким образом, я пытаюсь добавить некоторую вспышку к развитию, а также практике некоторые методы разработки DDD.

Flare обычно не является желательным качеством для проекта и может быть контрпродуктивным, приводя к разработке на основе аббревиатур, разработке на основе резюме и т. д. То же самое относится и к DDD - не пытайтесь применять тактические паттерны DDD, не понимая их недостатков.

Один из этих агрегатных корней имеет ссылку на другой агрегат Корень

Ссылки между ARs должны быть ограничены ссылками на идентичность, а не ссылками на объект, где это возможно. AR должен определить границу согласованности, которая не обязательно приведет к модели, которая отражает реальность самым естественным образом. Выражение отношений между клиентом и PO может быть выполнено с помощью ссылки на личность - PO имеет идентификатор клиента на нем. Взгляните на эффективный агрегатный дизайн вон Вернона Для получения дополнительной информации.

Может быть, это должно быть частью заказа на покупку AR?

Любые модификации состояния сущности должны быть инкапсулированы сущностью. Доменные службы могут предоставлять функциональные возможности сущностям, которые естественным образом не вписываются в существующую сущность.

В настоящее время хранилища выполняют свою работу по сохранению данных. из базы данных и" заполняет " AR-ы данными. когда АР "сохраняет" его, хранилище, сохраняет все, что нуждается в сохранении. То Репозиторий заказов на покупку используется клиентом AR, поэтому клиент может загрузите все заказы на покупку, которые он может содержать.. Надеюсь, я в курсе. правильное направление.

Ни AR, ни сущности, ни объекты value не должны ссылаться на репозиторий или вызывать в нем какие-либо методы. Репозитории должны вызываться службой приложений. Маловероятно, что клиент AR должен содержать коллекцию POs. Вместо этого список PO клиента должен быть предоставлен репозиторием PO. Отношения таковы тем не менее, он просто реализован с репозиторием вместо обхода объекта. Причина этого восходит к тому, что AR является границей согласованности.

Контроллер в настоящее время работает через клиентскую фабрику

Фабрика должна использоваться только для создания новых экземпляров, а не для доступа к сохраненным экземплярам - для этого и существует репозиторий. Вы можете создать слой представления (MVC) несколькими способами. Типичная архитектура DDD должна иметь ссылки на контроллеры служба приложения. Службы приложений, в свою очередь, реализуют конкретные варианты использования, координируя репозитории, фабрики, службы инфраструктуры и вызывая поведение в ARs. Допустим, у вас есть прецедент, когда клиент создает новый PO. Код будет выглядеть примерно так:
public ActionResult CreatePurchaseOrder(CreatePurchaseOrderViewModel viewModel)
{
   var poData = viewModel.CreatePurchaseOrderData();

   this.purchaseOrderAppService.CreatePurchaseOrder(viewModel.ClientId, poData);

   return RedirectToAction("Index");
}

...

public class PurchaseOrderAppService
{
  readonly IClientRepository clientDb;
  readonly IPurchaseOrderRepository poDb;

  public void CreatePurchaseOrder(int clientId, PurchaseOrderData poData)
  {
     var client = this.clientDb.Get(clientId);

     var purchaseOrder = PurchaseOrderFactor.Create(client, poData);

     this.poDb.Add(purchaseOrder);
     this.poDt.Commit(); // committing of Unit of Work should be moved up to infrastructure level
  }
}

Взгляните на это DDDSample.Net project , который содержит реализацию пользовательского интерфейса MVC для проекта DDD.