Domain-Driven-Design: dipendenze esterne nel problema Entity

19

Vorrei avviare Domain-Driven-Design, ma ci sono diversi problemi che vorrei risolvere prima di iniziare:)

Immaginiamo di avere un gruppo e utenti e quando l'utente vuole unirsi a un gruppo, sto chiamando il metodo groupsService.AddUserToGroup(group, user) . In DDD dovrei fare group.JoinUser(user) , che sembra piuttosto buono.

Il problema si verifica se sono presenti alcune regole di convalida per l'aggiunta di un utente o se alcune attività esterne devono essere avviate quando l'utente viene aggiunto al gruppo. Avere questi compiti porterà all'entità con dipendenze esterne.

Un esempio potrebbe essere - una restrizione che l'utente può partecipare solo a 3 gruppi max. Ciò richiederà chiamate DB dal metodo group.JoinUser per convalidarlo.

Ma il fatto che un'entità dipenda da alcuni servizi / classi esterni non mi sembra così buona e "naturale".

Qual è il modo corretto di affrontarlo in DDD?

    
posta Shaddix 13.08.2011 - 17:58
fonte

2 risposte

14

Let's imagine I have a Groups and Users and when user wants to join a group, I'm calling groupsService.AddUserToGroup(group, user) method. In DDD I should do group.JoinUser(user), which looks pretty good.

Ma DDD ti incoraggia anche a utilizzare servizi (stateless) per eseguire attività, se l'attività in corso è troppo complessa o non si adatta a un modello di entità. Va bene avere servizi nel livello dominio. Ma i servizi nel livello dominio dovrebbero includere solo la logica aziendale. Le attività esterne e la logica dell'applicazione (come l'invio di una e-mail), d'altra parte, dovrebbero utilizzare il servizio di dominio nel livello dell'applicazione, in cui è possibile disporre ad esempio di un servizio (applicazione) separato.

The problem appears if I there are some validation rules for adding a user ...

Le regole di convalida appartengono al modello di dominio! Dovrebbero essere incapsulati all'interno degli oggetti del dominio (entità ecc.).

... or some external tasks need to be started when user is added to the group. Having these tasks will lead to the entity having external dependencies.

Anche se non so che tipo di attività esterna stai parlando, presumo che sia qualcosa come inviare un'e-mail, ecc. Ma questo non fa realmente parte del tuo modello di dominio. Dovrebbe vivere nel livello di applicazione e rimanere lì imho. Puoi avere un servizio nel tuo livello applicativo che opera su servizi e entità di dominio per eseguire tali compiti.

But the fact that an Entity depends on some external services/classes doesn't seem so good and "natural" to me.

È innaturale e non dovrebbe accadere. L'entità non dovrebbe sapere di cose che non sono di sua competenza. I servizi dovrebbero essere utilizzati per orchestrare le interazioni tra entità.

What's the proper way to deal with this in DDD?

Nel tuo caso, la relazione dovrebbe probabilmente essere bidirezionale. Se l'utente si unisce al gruppo o al gruppo, l'utente dipende dal tuo dominio. L'utente si unisce al gruppo? O l'utente è stato aggiunto a un gruppo? Come funziona nel tuo dominio?

Ad ogni modo, hai una relazione bidirezionale e puoi quindi determinare la quantità di gruppi a cui l'utente appartiene già all'interno dell'aggregato utente. Se si passa l'utente al gruppo o il gruppo all'utente è tecnicamente banale una volta determinata la classe responsabile.

La convalida dovrebbe quindi essere eseguita dall'entità. Il tutto è chiamato da un servizio del livello applicazione che può anche fare cose tecniche, come l'invio di email ecc.

Tuttavia, se la logica di validazione è davvero complessa, un servizio di dominio potrebbe essere una soluzione migliore. In tal caso, incapsula le regole aziendali e quindi chiamalo dal livello applicazione.

    
risposta data 13.08.2011 - 20:46
fonte
3

Il modo in cui affronterei il problema della convalida è in questo modo: Crea un servizio di dominio chiamato MembershipService :

class MembershipService : IMembershipService
{
   public MembershipService(IGroupRepository groupRepository)
   { 
     _groupRepository = groupRepository;
   }
   public int NumberOfGroupsAssignedTo(UserId userId)
   {
        return _groupsRepository.NumberOfGroupsAssignedTo(userId);
   }
}

L'entità di gruppo deve essere iniettata con IMemberShipService . Questo può essere fatto a livello di classe o di metodo. Supponiamo che lo facciamo a livello di metodo.

class Group{

   public void JoinUser(User user, IMembershipService membershipService)
   {
       if(membershipService.NumberOfGroupsAssignedTo(user.UserId) >= 3)
         throw new BusinessException("User assigned to more than 3 groups. Cannot proceed");

       // do some more stuff
   }
}

Il servizio Applicazione: GroupService può essere iniettato con IMemberShipService utilizzando Iniezione del costruttore, che può quindi passare al metodo JoinUser della classe Group .

    
risposta data 25.11.2014 - 12:03
fonte

Leggi altre domande sui tag