доступ к данным в DDD? - PullRequest
       39

доступ к данным в DDD?

10 голосов
/ 17 сентября 2008

После прочтения книг Эвана и Нильссона я все еще не уверен, как управлять доступом к данным в проекте, управляемом доменом. Если методы CRUD являются частью репозиториев, т. Е. OrderRepository.GetOrdersByCustomer (customer), или они должны быть частью сущностей: Customer.GetOrders (). Последний подход кажется больше ОО, но он будет распределять доступ к данным для одного типа сущности среди нескольких объектов, то есть Customer.GetOrders (), Invoice.GetOrders (), ShipmentBatch.GetOrders () и т. Д. А как насчет вставки и обновления?

Ответы [ 6 ]

15 голосов
/ 17 сентября 2008

CRUD-методы должны быть частью репозитория ... ish. Но я думаю, вы должны спросить, почему у вас есть куча методов CRUD. Что они действительно делают? Для чего они действительно ? Если вы на самом деле вызываете шаблоны доступа к данным, которые использует ваше приложение, я думаю, что это делает хранилище намного более полезным и избавляет вас от необходимости выполнять операцию дробовика, когда в вашем домене происходят определенные типы изменений.

CustomerRepo.GetThoseWhoHaventPaidTheirBill()

// or

GetCustomer(new HaventPaidBillSpecification())

// is better than

foreach (var customer in GetCustomer()) {
    /* logic leaking all over the floor */
}

Методы типа «Сохранить» также должны быть частью репозитория.

Если у вас есть агрегированные корни, это избавит вас от взрыва репозитория или от рассредоточенной логики: у вас нет 4х # шаблонов доступа к данным сущностей, только те, которые вы фактически используете в агрегированных корнях .

Это мои $ .02.

5 голосов
/ 17 сентября 2008

DDD обычно предпочитает шаблон репозитория по сравнению с шаблоном активной записи, на который вы намекаете с помощью Customer.Save.

Одним из недостатков модели Active Record является то, что она в значительной степени предполагает одну модель персистентности, за исключением некоторого особенно навязчивого кода (в большинстве языков).

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

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

Если у вас нет особого подхода к доменной логике, вам, вероятно, не нужен DDD. ActiveRecord вполне подходит для множества проблем, особенно если у вас есть в основном данные и немного логики.

4 голосов
/ 20 сентября 2008

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

customer.Orders;

Итак, чтобы ответить на ваш вопрос, операции CRUD присутствуют в совокупных корневых репозиториях.

CustomerRepository.Add(customer);
CustomerRepository.Get(customerID);
CustomerRepository.Save(customer);
CustomerRepository.Delete(customer);
3 голосов
/ 17 сентября 2008

Я сделал это обоими способами, о которых вы говорите. Сейчас я предпочитаю постоянный невежественный (или PONO - Plain Ole '.Net Object) метод, в котором ваши доменные классы беспокоятся только о том, чтобы быть доменными классами. Они ничего не знают о том, как они сохраняются или даже сохраняются. Конечно, иногда вы должны быть прагматичными по этому поводу и учитывать такие вещи, как Id (но даже тогда я просто использую супертип слоя, который имеет Id, поэтому у меня может быть одна точка, в которой живут такие вещи, как значение по умолчанию)

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

Одна вещь, на которую стоит обратить внимание, это метод вздутия, от которого могут пострадать репозитории. GetOrderbyCustomer .. GetAllOrders .. GetOrders30DaysOld .. и т. Д. И т. Д. Одним из хороших решений этой проблемы является рассмотрение шаблона Query Object. И тогда ваши репозитории могут просто принять объект запроса для выполнения.

Я бы также настоятельно рекомендовал изучить что-то вроде NHibernate. Он включает в себя множество концепций, которые делают хранилища такими полезными (объекты Identity Map, Cache, Query ..)

2 голосов
/ 17 сентября 2008

Даже в DDD классы и процедуры доступа к данным отделены от сущностей.

Причины,

  1. Улучшается тестируемость
  2. Разделение концернов и модульная конструкция
  3. Больше возможностей в долгосрочной перспективе при добавлении сущностей, подпрограмм

Я не эксперт, просто мое мнение.

1 голос
/ 17 сентября 2008

Раздражает то, что Нильссон применяет DDD & P, так это то, что он всегда начинает с «Я бы не делал этого в реальных приложениях, но ...», а затем следует его пример. Вернуться к теме: я думаю, что OrderRepository.GetOrdersByCustomer (клиент) - это путь, но есть также обсуждение в списке рассылки ALT.Net (http://tech.groups.yahoo.com/group/altdotnet/) о DDD.

...