2011-10-16 13 views
14

Il mio team si impegna molto a rispettare Domain Driven Design come strategia architetturale. Ma, il più delle volte, le nostre entità di dominio sono piuttosto enimiche. Vorremmo mettere più business/dominio sul comportamento delle nostre entità di dominio.DDD: Che tipo di comportamento dovrei inserire in un'entità di dominio?

Ad esempio, Active Record consente l'accesso ai dati sull'entità. Non lo vogliamo perché usiamo volentieri il pattern del repository per l'accesso ai dati.

Inoltre, progettiamo il nostro software come SOLID (i cinque principi di progettazione software messi insieme da Uncle Bob). Quindi, per noi è importante prestare attenzione alla singola responsabilità, alla chiusura aperta, alla liskov, alla segregazione dell'interfaccia e all'inversione di dipendenza durante la progettazione delle nostre entità.

Quindi, che tipo di comportamento dovremmo includere? Di che tipo dovremmo stare lontani?

+0

La singola responsabilità è piuttosto antitetica alla progettazione basata su domini. Abbiamo avuto un'interessante discussione su questo incontro al NYCDDD un paio di mesi fa ... – Domenic

+0

Sarei interessato a quella discussione. Non trovo che sia il caso –

risposta

19

È passato quasi un anno da quando ho fatto questa domanda e io e il mio team abbiamo imparato parecchio da allora. Ecco come risponderei a questa domanda oggi:

Il dominio dovrebbe rappresentare (in codice) cosa è o cosa fa l'attività (nella vita reale). Le entità di dominio, quindi, sono gli artefatti o gli attori trovati in quell'attività reale. Che tipo di comportamento hanno questi artefatti e attori di vita? Tutto. A sua volta, che tipo di comportamento DOVREBBE le entità di dominio hanno su di loro? Tutto.

Ad esempio, nella vita reale, un manager può assumere un nuovo dipendente. La rappresentazione del dominio di questo dovrebbe includere entità come "manager" e "nuovo dipendente". Il manager è l'attore, qui.

//newEmployee comes from somewhere else... possibly the UI 
//someManagerId comes from the logged in user 
var manager = _repository.Get<Manager>(someManagerId); 
manager.Hire(newEmployee); 

Così, i modelli entity manager/riflette il comportamento del business vita reale, qui. L'alternativa è quella di ignorare l'entità responsabile come attore, e lo spingere verso l'angolo in modo da un pesante di sollevamento "servizio di dominio" può fare tutto il lavoro ... in questo modo:

//newEmployeeService comes from somewhere else... possibly injected using IOC 
newEmployeeService.Create(newEmployee, someManagerId); 

In un dominio anemico , dovresti utilizzare un servizio di dominio come questo per creare o assumere un dipendente. Funziona, ma non è espressivo e il comportamento non è così individuabile. Chi fa cosa? Perché il manager ha bisogno di creare un nuovo dipendente?


Credo che quando ho fatto la domanda in origine, ho voluto provare ad avviare di cui più comportamento nei miei entità, ma io davvero non sapevo come senza iniettare servizi nelle mie entità (per esempio, con l'iniezione del costruttore). Da allora, abbiamo imparato alcuni nuovi trucchi e le entità della nostra squadra sono super-espressive. Ecco, in poche parole, cosa stiamo facendo:

  1. Cerchiamo, quando possibile, di utilizzare le entità attore per esprimere la persona o la cosa che sta eseguendo l'azione.
  2. Gli attori dispongono di metodi che esprimono le azioni che possono eseguire
  3. Quando un servizio è necessario, viene iniettato come argomento nel metodo in cui viene utilizzato.
  4. Gli eventi del dominio vengono attivati ​​utilizzando BlingBag in ogni metodo su ogni entità di dominio per fornire l'estensibilità e dare alle entità la possibilità di autodeterminarsi.
+2

E il nuovo dipendente. È stato creato da una fabbrica o dal repository? Solleverà un evento di dominio per creazione? Gli eventi di dominio dovrebbero essere gestiti da repository o dovrebbero andare al di fuori del livello di dominio? Potrei chiedere troppo: D – inf3rno

+0

Sto anche cercando di fare lo stesso. Come call = marketer.call (client); inquiry = marketer.makeInquiry (client, date); im curioso come hai configurato il tuo Manager in ORM e il design del database. Gestore in un'eredità di tabelle singole? Sto eseguendo l'ereditarietà di una tabella singola ma non ho bisogno della colonna del discriminatore. in pratica gli attori hanno gli stessi dati solo con ruoli diversi. –

+0

+1 per il punto n. 3 (Quando è necessario un servizio, viene iniettato come argomento nel metodo in cui viene utilizzato). Ho visto questa sottigliezza eludere un sacco di persone (me compreso).Quando ci pensi, ha senso organizzarlo in questo modo piuttosto che usare l'iniezione del costruttore, in quanto chiarisce quali siano le dipendenze di ogni azione. – MetaFight

0

un comportamento che provo a inserire nel mio dominio, entità o oggetti valore.

convalida prima della persistenza. Convalida prima della transizione in un nuovo stato. Ad esempio, l'entità radice di un ordine aggregato può convalidare il suo stato interno e i suoi aggregati figli prima di passare allo stato Sent. minimizza le proprietà get set e usa gli oggetti valore il più possibile. Innanzitutto rende il modello più ricco di comportamenti. le entità diventano più descrittive. in secondo luogo, si mette di rado la propria entità in uno stato non valido se è necessario utilizzare metodi oggetto valore come il metodo ApplyAdress su un'entità persona che prende un oggetto Valore indirizzo come nel parametro.

cos'altro ... Info intelligence. usa la tua entità e i suoi oggetti valore per controllare e limitare le informazioni aggregate. come la personidentity può essere un oggetto di valore che gestisce l'unicità di una persona. incapsula ssn, ssn algoritm, gestisce il checksum di genere su ssn ecc.

+0

mandami una email se volessi scambiare discussioni più approfondite su ddd e comportamento. –

0

Il comportamento delle entità deve riflettere il modello di business. Ciò che può essere fatto ao da quell'entità è che il mondo degli affari dovrebbe essere sopmething che può essere fatto ao dalla classe di entità. Ad esempio:

In un sistema di acquisti online, è possibile aggiungere un prodotto al carrello. Così la classe spesa dovrebbe essere simile a questo:

public class Cart 
{ 
    //... 

    public void AddProduct(Product product) 
    { 
     ...code to add product to cart. 
    } 
} 

Si potrebbe sostenere che i methids dovrebbero riflettere i casi d'uso.

+0

o è il prodotto # AddToCart (Carrello) ??? – pinkpanther

3

Se devi chiedere quale comportamento dovresti inserire nell'entità del dominio, probabilmente non hai bisogno del DDD. Sto cercando di essere utile qui, perché ho avuto un sacco di dolore nel tentativo di adattarmi alla DDD in un posto a cui non apparteneva.

DDD o anche domain model sono modelli che possono essere seguiti dopo si scopre che la complessità del dominio è troppo alta per far funzionare qualsiasi altro modello. Quindi solo CRUD non è adatto per DDD. Dalla mia comprensione, DDD si adatta quando si dispone di un contesto limitato che contiene complesso regole aziendali che devono essere eseguite prima dello stato di transizione per la radice aggregata. Quindi non includerei la convalida nella definizione di complesso.

Il tipo di comportamento che si desidera inserire nelle entità è intimamente correlato al problema aziendale che si sta tentando di risolvere. La preoccupazione per la persistenza (repository, ecc.) Dovrebbe venire dopo (infatti, la persistenza potrebbe trovarsi in un flusso di lavoro o in un archivio di eventi).

Spero che questo aiuti.