In der Debatte von Rich vs. Anemic Domain Models steckt das Internet voller philosophischer Ratschläge, aber es fehlen maßgebliche Beispiele. Ziel dieser Frage ist es, definitive Richtlinien und konkrete Beispiele für geeignete domänengetriebene Designmodelle zu finden. (Idealerweise in C #.)
Für ein reales Beispiel scheint diese Implementierung von DDD falsch zu sein:
Bei den folgenden WorkItem-Domänenmodellen handelt es sich nur um Eigenschaftensäcke, die von Entity Framework für eine Code-First-Datenbank verwendet werden. Per Fowler ist es anämisch .
Die WorkItemService-Schicht ist anscheinend eine häufige Fehleinschätzung von Domain Services. Es enthält die gesamte Verhaltens- / Geschäftslogik für das WorkItem. Per Yemelyanov und andere ist es prozedural . (S. 6)
Also, wenn das unten stehende falsch ist, wie kann ich es richtig machen?
Das Verhalten, dh AddStatusUpdate oder Checkout , sollte zur WorkItem-Klasse gehören.
Welche Abhängigkeiten sollte das WorkItem-Modell haben?
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();
}
}
}
(Dieses Beispiel wurde vereinfacht, um besser lesbar zu sein. Der Code ist definitiv immer noch klobig, da es sich um einen verwirrten Versuch handelt. Das Verhalten der Domäne war jedoch: Aktualisierungsstatus durch Hinzufügen des neuen Status zum Archivverlauf. Letztendlich stimme ich den anderen Antworten zu könnte nur von CRUD gehandhabt werden.)
Aktualisieren
@AlexeyZimarev gab die beste Antwort, ein perfektes Video zu diesem Thema in C # von Jimmy Bogard, aber es wurde anscheinend in einen Kommentar unten verschoben, weil es nicht genügend Informationen über den Link hinaus gab. Ich habe einen groben Entwurf meiner Notizen, die das Video in meiner Antwort unten zusammenfassen. Bitte kommentieren Sie die Antwort mit eventuellen Korrekturen. Das Video ist eine Stunde lang, aber sehr sehenswert.
Update - 2 Jahre später
Ich denke, es ist ein Zeichen für die beginnende Reife von DDD, dass ich auch nach 2-jährigem Studium nicht versprechen kann, dass ich den "richtigen Weg" dazu kenne. Allgegenwärtige Sprache, aggregierte Wurzeln und sein Ansatz für verhaltensorientiertes Design sind die wertvollen Beiträge von DDD für die Branche. Beharrlichkeit, Ignoranz und Event-Sourcing sorgen für Verwirrung, und ich denke, dass eine solche Philosophie sie von einer breiteren Akzeptanz abhält. Aber wenn ich diesen Code mit dem, was ich gelernt habe, noch einmal machen müsste, würde er ungefähr so aussehen:
Ich freue mich immer noch über Antworten auf diesen (sehr aktiven) Beitrag, der einen Code für bewährte Methoden für ein gültiges Domain-Modell enthält.
"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" im Entity Framework-Jargon ist nicht dasselbe wie "Entities" im "Domain Model"