Nel dibattito sui modelli di dominio Rich vs. Anemic, Internet è piena di consigli filosofici ma a corto di esempi autorevoli. L'obiettivo di questa domanda è trovare linee guida definitive ed esempi concreti di modelli di progettazione basati su dominio adeguati. (Idealmente in C #.)
Per un esempio reale, questa implementazione di DDD sembra essere sbagliata:
I modelli di dominio WorkItem di seguito non sono altro che sacche di proprietà, utilizzate da Entity Framework per un database in codice. Per Fowler, è anemico .
Il livello WorkItemService è apparentemente una percezione errata comune dei servizi di dominio; contiene tutta la logica di comportamento / business per WorkItem. Per Yemelyanov e altri, è procedurale . (pag.6)
Quindi, se il seguito è sbagliato, come posso farlo bene?
Il comportamento, ovvero AddStatusUpdate o Checkout , dovrebbe appartenere alla classe WorkItem corretta?
Quali dipendenze dovrebbe avere il modello 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();
}
}
}
(Questo esempio è stato semplificato per essere più leggibile. Il codice è sicuramente ancora goffo, perché è un tentativo confuso, ma il comportamento del dominio è stato: aggiorna lo stato aggiungendo il nuovo stato alla cronologia dell'archivio. Alla fine sono d'accordo con le altre risposte, questo potrebbe essere gestito da CRUD.)
Aggiornare
@AlexeyZimarev ha dato la risposta migliore, un video perfetto sull'argomento in C # di Jimmy Bogard, ma apparentemente è stato spostato in un commento qui sotto perché non ha fornito abbastanza informazioni oltre il link. Ho una bozza dei miei appunti che riassume il video nella mia risposta di seguito. Non esitate a commentare la risposta con eventuali correzioni. Il video dura un'ora ma vale davvero la pena guardarlo.
Aggiornamento - 2 anni dopo
Penso che sia un segno della nascente maturità di DDD che anche dopo averlo studiato per 2 anni, non posso ancora promettere di conoscere il "modo giusto" di farlo. Il linguaggio diffuso, le radici aggregate e il suo approccio alla progettazione orientata al comportamento sono i preziosi contributi di DDD al settore. L'ignoranza di persistenza e l'approvvigionamento di eventi causano confusione, e penso che una filosofia del genere la trattiene da un'adozione più ampia. Ma se dovessi ripetere questo codice, con quello che ho imparato, penso che sarebbe simile a questo:
Sono ancora felice di ricevere risposte a questo post (molto attivo) che fornisca qualsiasi codice di best practice per un modello di dominio valido.
"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à" nel gergo Entity Framework non sono le stesse di "Entità" come in "Modello di dominio"