Dans le débat sur les modèles de domaine Rich vs. Anemic, Internet regorge de conseils philosophiques, mais ne contient que des exemples faisant autorité. L’objectif de cette question est de trouver des directives définitives et des exemples concrets de modèles de conception pilotés par domaine appropriés. (Idéalement en C #.)
Pour un exemple concret, cette implémentation de DDD semble être fausse:
Les modèles de domaine WorkItem ci-dessous ne sont que des sacs de propriétés, utilisés par Entity Framework pour une base de données code-first. Per Fowler, c'est anémique .
La couche WorkItemService est apparemment une perception erronée courante des services de domaine; il contient toute la logique comportementale / métier du workItem. Per Yemelyanov et d’autres, c’est une procédure . (p. 6)
Donc, si le dessous est faux, comment puis-je le corriger?
Le comportement, à savoir AddStatusUpdate ou Checkout , devrait appartenir à la classe WorkItem correcte?
Quelles dépendances le modèle WorkItem devrait-il avoir?
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();
}
}
}
(Cet exemple a été simplifié pour être plus lisible. Le code est certainement toujours maladroit, car c'est une tentative confuse, mais le comportement du domaine était le suivant: statut de la mise à jour en ajoutant le nouveau statut à l'historique des archives. En fin de compte, je suis d'accord avec les autres pourrait juste être manipulé par CRUD.)
Mise à jour
@AlexeyZimarev a donné la meilleure réponse, une vidéo parfaite sur le sujet en C # de Jimmy Bogard, mais elle a apparemment été déplacée dans un commentaire ci-dessous car elle ne donnait pas suffisamment d'informations au-delà du lien. J'ai un brouillon de mes notes résumant la vidéo dans la réponse ci-dessous. N'hésitez pas à commenter la réponse avec des corrections. La vidéo dure une heure mais vaut vraiment la peine d'être visionnée.
Mise à jour - 2 ans plus tard
Je pense que c'est un signe de la maturité naissante de DDD: même après l'avoir étudié pendant 2 ans, je ne peux toujours pas promettre que je connais la "bonne façon" de le faire. Le langage omniprésent, les racines globales et son approche de la conception axée sur le comportement constituent les contributions précieuses de DDD au secteur. L'ignorance de la persistance et le repérage des événements créent de la confusion, et je pense qu'une telle philosophie l'empêche d'adopter plus largement. Mais si je devais refaire ce code, avec ce que j'ai appris, je pense que cela ressemblerait à ceci:
Je suis toujours heureux de recevoir des réponses à ce message (très actif) fournissant un code de bonne pratique pour un modèle de domaine valide.
"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"
. "Entités" dans le jargon du Entity Framework ne sont pas les mêmes que "Entités" mais dans "Modèle de domaine"