У дискусіях про доменні моделі Річ проти Анемій Інтернет є сповненим філософських порад, але коротким на авторитетні приклади. Мета цього питання - знайти остаточні вказівки та конкретні приклади правильних моделей, керованих доменом. (Ідеально в 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 # від Jimmy Bogard, але це, очевидно, було перенесено в коментар нижче, оскільки він не дав достатньо інформації за посиланням. У мене є приблизний проект моїх записок, узагальнюючи відео у своїй відповіді нижче. Будь ласка, коментуйте відповідь з будь-якими виправленнями. Відео триває годину, але його дуже варто переглянути.
Оновлення - через 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"
. "Entities" в жаргоні Entity Framework - це не те саме, що "Entities", як у "Domain Domain"