2013-06-04 8 views
5

Stiamo provando ad adottare Domain-Driven Design nel nostro progetto per la prima volta. Il problema che ho è con le associazioni tra entità. Come li fai bene?Il modo giusto per implementare le associazioni in DDD?

Dire, ho entità Employee e Contract, una semplice associazione uno-a-molti. Come lo modifico?

Opzione 1: Aggregato.

Problema: Il problema qui è che, se ho capito bene, tutte le entità in un aggregato devono essere caricate quando viene creato un oggetto aggregato. Non riesco a caricare le entità pigre quando sono necessarie perché richiederebbe il riferimento a un repository di un'entità, che a quanto pare non è buona. Ma recuperare tutti i contratti di un dipendente dal database ogni volta sarebbe un grosso problema di prestazioni.

Opzione 2: Recupero contratti di un dipendente utilizzando un repository (ad esempio ContractRepository.GetContractsForEmployee()) e aggiungendo EmployeeId proprietà Contract di classe.

Problema: rende difficile inserire qualsiasi logica aziendale in entità. Mi piacerebbe avere un metodo, per esempio, Employee.Dismiss(), ma sarebbe anche necessario aggiornare il contratto del dipendente. Ciò significa che avrei bisogno di mettere questa logica in un servizio. Il problema è che non riesco a pensare a molte logiche che funzionano solo su un Employee e quindi il modello diventerebbe alquanto anemico, con la maggior parte dei servizi logici interni.

Come gestite questi problemi in DDD?

+1

Una volta che stai pensando 'una semplice associazione uno-a-molti' non stai facendo DDD, stai facendo la progettazione dello schema del database. Le associazioni tra entità dovrebbero essere comportamenti. Un Dipendente non può licenziarsi, deve essere licenziato (da un'altra entità che ha l'autorità per farlo). L'opzione 2 è quella giusta. Non devi inventare un sacco di comportamento per un'entità. Se un oggetto di dominio è molto semplice nel business reale, modellalo in questo modo. Importa come il Dominio definisce il concetto (la semantica) e non quanti metodi ha l'oggetto. – MikeSW

+0

MikeSW è corretto. Un aspetto molto importante della DDD è Ubiquitous Language. Il modo in cui parli del dominio DEVE essere il modo in cui l'esperto del dominio parla del dominio, altrimenti il ​​codice diventa scomodo e non intuitivo. Sembra banale, ma se capisci bene, le Entità iniziano a suggerire un comportamento. per esempio. Employee.Resign(); Contract.Terminate(); – Asher

risposta

2

Questa è solo la mia opinione su ... senza conoscere il tuo dominio.

Innanzitutto, here è una buona risorsa da leggere (parte su Aggregati e radici).

In DDD terminologia, Employee e Contract sono entrambi entità (perché entrambi hanno un'identità).

"aggregati tracciare un confine intorno a uno o più entità e anche:. ogni aggregato ha un'Entità della radice, che è l'unico membro della Aggregate che qualsiasi oggetto al di fuori l'aggregato è permesso di tenere un riferimento."

La domanda è: fare Employee e Contract forma un aggregato, con Employee essendo l'entità radice Ovviamente no, perché altre entità del dominio potrebbe anche avere un riferimento a un contract, e l'ID del contratto di sono globalmente univoco, no? . solo all'interno di un Customer

Quindi, tenendo conto di queste regole, Employee e Contract sono entrambi radici di aggregazione

Poi:. "radici solo aggregati può essere ottenuto direttamente con le query; Quindi questo significa che dovremmo avere un repository per radice aggregato."

Quindi, in questo caso, abbiamo un EmployeeRepository e ContractRepository.

Prendendo tutto questo in considerazione, non voglio aggiungere una relazione tra dipendenti e contratti nel modello di dominio, ma trattarli separatamente.Dopo tutto, se hai bisogno di un Employee, non hai necessariamente bisogno del suo contracts, sono entrambi aspetti diversi.

L'opzione 2 è ciò che sceglierei: usa lo ContractRepository per ottenere i contratti a cui sei interessato. E se necessario, co uld aggiungere un servizio di dominio che è responsabile per l'aggregazione di dipendenti e contratti, se necessario.

Se si definisce anche un'entità Company, il licenziamento di un dipendente potrebbe essere il lavoro di tale entità.

0

È necessario trovare i veri invarianti.

Qui è possibile avere un invariante come: non è possibile eliminare uno Employee che è già stato rimosso.

Se questo è l'unico invariante reale, è possibile creare un aggregato Employee, che avrebbe solo gli ID dei contratti associati.

Contract sarebbe un altro aggregato (se necessario).

Se il metodo dismiss() ha esito positivo, è possibile caricare i contratti necessari e apportare le modifiche necessarie.

1

Recentemente siamo entrati nell'approccio DDD. Se dovessi farlo, vorrei avere la seguente (attributi sono semplificate per brevità):

public class Employee() { 

    String name; 
    Set<ContractNumber> contracts; 

    public void addContract(ContractNumber contractNumber) { 
     this.contracts.add(contractNumber); 
    } 

} 

public class Contract() { 
    ContractNumber contractNumber; 
    Date effectiveDate; 
} 

public class ContractNumber() { 
    String contractNumber; 
} 

CONTRACTNUMBER è un oggetto di valore che si riferisce a dal di dentro dei dipendenti. In questo esempio, Employee è all'interno di un BoundedContext che si occupa dei Dipendenti e dei rispettivi contratti. Potrebbero esserci altre rappresentazioni del Dipendente in altri contesti limitati.

Come discusso in altre risposte, ci saranno repository per Dipendente e Contratto.