W debacie na temat modeli domen Rich vs. Anemic Internet jest pełen porad filozoficznych, ale brakuje autorytatywnych przykładów. Celem tego pytania jest znalezienie ostatecznych wytycznych i konkretnych przykładów prawidłowych modeli projektowania opartych na domenie. (Idealnie w C #.)
Na przykład w rzeczywistości ta implementacja DDD wydaje się nieprawidłowa:
Poniższe modele domen WorkItem to tylko torby właściwości, używane przez Entity Framework dla bazy danych zawierającej kod. Według Fowlera jest to niedokrwistość .
Warstwa WorkItemService jest najwyraźniej częstym błędnym postrzeganiem usług domenowych; zawiera całą logikę zachowania / biznesu dla WorkItem. Według Jemelyanova i innych jest to postępowanie proceduralne . (str. 6)
Więc jeśli poniższe informacje są nieprawidłowe, jak mogę to naprawić?
Zachowanie, tj. AddStatusUpdate lub Checkout , powinno należeć do klasy WorkItem, prawda?
Jakie zależności powinien mieć model 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();
}
}
}
(Ten przykład został uproszczony, aby był bardziej czytelny. Kod jest zdecydowanie nieporadny, ponieważ jest to myląca próba, ale zachowanie domeny brzmiało: aktualizacja statusu poprzez dodanie nowego statusu do historii archiwum. Ostatecznie zgadzam się z innymi odpowiedziami, to może po prostu obsłużyć CRUD).
Aktualizacja
@AlexeyZimarev udzielił najlepszej odpowiedzi, doskonałego filmu na ten temat w C # autorstwa Jimmy'ego Bogarda, ale najwyraźniej został przeniesiony do komentarza poniżej, ponieważ nie podał wystarczającej ilości informacji poza linkiem. Mam wstępny szkic notatek podsumowujących wideo w mojej odpowiedzi poniżej. Prosimy o komentarz w odpowiedzi z wszelkimi poprawkami. Film trwa godzinę, ale warto go obejrzeć.
Aktualizacja - 2 lata później
Myślę, że to oznaka rodzącej się dojrzałości DDD, że nawet po studiowaniu przez 2 lata nadal nie mogę obiecać, że znam „właściwy sposób” robienia tego. Wszechobecny język, zagregowane korzenie i jego podejście do projektowania zorientowanego na zachowanie stanowią cenny wkład DDD w przemysł. Trwałość ignorancji i pozyskiwania zdarzeń powoduje zamieszanie i myślę, że taka filozofia powstrzymuje ją przed szerszym przyjęciem. Ale gdybym musiał zrobić ten kod od nowa, z tym, czego się nauczyłem, myślę, że wyglądałby mniej więcej tak:
Nadal z zadowoleniem przyjmuję wszelkie odpowiedzi na ten (bardzo aktywny) post, który zawiera kod najlepszych praktyk dla prawidłowego modelu domeny.
"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"
. „Encje” w żargonie Entity Framework nie są tym samym co „Encje” jak w „Modelu domeny”