В дебатах моделей предметной области Rich против Anemic Интернет полон философских советов, но не хватает авторитетных примеров. Цель этого вопроса - найти четкие рекомендации и конкретные примеры правильных моделей проектирования на основе доменов. (В идеале в C #.)
Для реального примера эта реализация DDD кажется неправильной:
Приведенные ниже модели доменов WorkItem представляют собой не что иное, как пакеты свойств, используемые Entity Framework для базы данных с первым кодом. По Фаулеру, это анемично .
Уровень WorkItemService, по-видимому, является распространенным заблуждением доменных служб; он содержит всю поведенческую / бизнес-логику для WorkItem. По Емельянову и другим, это процедурно . (стр. 6)
Так что, если ниже не так, как я могу сделать это правильно?
Поведение, т.е. AddStatusUpdate или Checkout , должно принадлежать в классе WorkItem правильно?
Какие зависимости должна иметь модель WorkItem?
public class WorkItemService : IWorkItemService {
private IUnitOfWorkFactory _unitOfWorkFactory;
//using Unity for dependency injection
public WorkItemService(IUnitOfWorkFactory unitOfWorkFactory) {
_unitOfWorkFactory = unitOfWorkFactory;
}
public void AddStatusUpdate(int workItemId, int statusId) {
using (var unitOfWork = _unitOfWorkFactory.GetUnitOfWork<IWorkItemUnitOfWork>()) {
var workItemRepo = unitOfWork.WorkItemRepository;
var workItemStatusRepo = unitOfWork.WorkItemStatusRepository;
var workItem = workItemRepo.Read(wi => wi.Id == workItemId).FirstOrDefault();
if (workItem == null)
throw new ArgumentException(string.Format(@"The provided WorkItem Id '{0}' is not recognized", workItemId), "workItemId");
var status = workItemStatusRepo.Read(s => s.Id == statusId).FirstOrDefault();
if (status == null)
throw new ArgumentException(string.Format(@"The provided Status Id '{0}' is not recognized", statusId), "statusId");
workItem.StatusHistory.Add(status);
workItemRepo.Update(workItem);
unitOfWork.Save();
}
}
}
(Этот пример был упрощен, чтобы быть более читабельным. Код определенно все еще неуклюжий, потому что это ошибочная попытка, но поведение домена было следующим: обновить статус, добавив новый статус в историю архива. В конечном счете, я согласен с другими ответами, это может быть обработан CRUD.)
Обновить
@AlexeyZimarev дал лучший ответ - идеальное видео на эту тему в C # от Джимми Богарда, но, очевидно, оно было перемещено в комментарий ниже, потому что оно не давало достаточно информации, кроме ссылки. У меня есть черновик моих заметок с кратким изложением видео в моем ответе ниже. Пожалуйста, не стесняйтесь комментировать ответ с любыми исправлениями. Видео длится час, но его стоит посмотреть.
Обновление - 2 года спустя
Я думаю, что это признак зарождающейся зрелости DDD, что даже после изучения его в течение 2 лет, я все еще не могу обещать, что знаю «правильный способ» сделать это. Вездесущий язык, совокупные корни и его подход к поведенческому дизайну являются ценным вкладом DDD в отрасль. Постоянное невежество и источники событий приводят к путанице, и я думаю, что такая философия удерживает ее от более широкого принятия. Но если бы мне пришлось делать этот код снова, с тем, что я узнал, я думаю, это выглядело бы примерно так:
Я по-прежнему приветствую любые ответы на этот (очень активный) пост, в которых приведен любой передовой код для правильной доменной модели.
"I don't want to duplicate all my entities into DTOs simply because I don't need it and it violates DRY, and I also don't want my client application to take a dependency on EntityFramework.dll"
. «Сущности» в жаргоне Entity Framework - это не то же самое, что «сущности», как и в «Модель предметной области»