Identificazione dei servizi di dominio e dei servizi di applicazione durante il DDD

3

- Sto cercando di capire come identificare i servizi applicativi nella mia applicazione. Penso di poter identificare un servizio di dominio di 2 cose:

  1. Agisce come facciata per il repository.
  2. Detiene la logica aziendale che non può essere incapsulata in una singola entità.

Quindi ho pensato a questo caso di utilizzo semplice a cui sto lavorando attualmente:

Un amministratore dovrebbe essere in grado di escludere un determinato utente. L'operazione deve essere registrata e un'email deve essere inviata all'utente bannato.

Ho un UserRepository che ha una funzione getUserById() . Ho un'entità User che ha una funzione ban() .
Creerò un UserService come questo:

class UserService{
    static void banUser(int userId){
          User user= UserRepository.getUserById(userId);
          user.ban();
          UserRepository.update(user);
    }
}

La userId è una variabile POST che riceverò nel mio Controller da un modulo web.

Ora dove va la registrazione? Devo registrare il processo di ban due volte prima e dopo l'operazione ex:

Logger.log("Attempting to ban user with id:"+userId);
//user gets banned 
Logger.log("user banned successfully.");

In secondo luogo, ho bisogno di inviare una mail all'utente. dove dovrebbe andare la chiamata?

Ho pensato di inserire la registrazione e l'email è la classe UserService stessa, ma penso che ci siano soluzioni migliori.

Terzo, dove si adattano tutti i servizi applicativi?

    
posta Songo 19.02.2013 - 19:42
fonte

3 risposte

3

class UserService{
    public public UserService(IUserRepository repo, INotificationService notification)
    {
      this.UserRepository = repo;
      this.Notification = notification;
    }
    public void BanUser(int userId){
          User user= UserRepository.getUserById(userId);
          user.ban();
          Notification.NotifyBanned(user);
    }
}
Quando si parla di registrazione, è possibile scegliere molte soluzioni. Accedi al metodo BanUser. Crea logger per classe (come fanno gli utenti di log4j / log4net). Oppure puoi iniettare ILogger in Ctor. O forse è una sorta di traccia Audit. Allora forse IUserAuditTrail sarebbe meglio?

public interface IUserAuditTrail
{
    void UserBanned(User user)
    void AccountCreated(User user)
}
o sth così. Oppure puoi aggiungere lo stile AOP di registrazione. Decora l'UserService con l'attributo e usa PostSharp o usa il contenitore IoC e configura l'intercettatore per gestire la registrazione per te. A meno che le operazioni di registrazione non siano funzioni aziendali e invece è solo per i programmatori, andrei a intercettatori. Altrimenti IAuditTrail o sth così.     
risposta data 19.02.2013 - 22:01
fonte
2

Servizio dominio vs servizio applicazione
Un servizio di dominio è una classe che contiene un comportamento che non appartiene ad alcuna altra entità o oggetto valore nel dominio. Niente a che vedere con il repository. Se modellino i ruoli dell'utente , molti servizi di dominio diventano metodi del ruolo stesso.

Invece i servizi applicativi sono l'interfaccia utilizzata dal mondo esterno per utilizzare il dominio. Pertanto, UserService è un servizio applicativo.

Gestione degli effetti collaterali tecnici
Io uso entità osservabili per gestire tali eventi di dominio.

In questo modo:

  • il repository può osservare un evento Banned e aggiornare lo stato di persistenza senza la necessità di una chiamata di save esplicita
  • il UserService può sottoscrivere l'evento con un gestore che registra e invia l'email solo se il comando ban() ha esito positivo.
risposta data 06.03.2013 - 23:36
fonte
0

Now where does the logging go?

Second, I need to send a mail to the user. where should the call go?

Consiglierei Domain Events. Crea due eventi: UserBanAttemptedEvent e UserBannedEvent (nota il tempo passato).

La logica per la registrazione e la notifica via email sta entrando nei gestori di eventi, creare due gestori UserBanAttemptedEventHandler e UserBannedEventHandler.

Le classi * payload semplicemente DTO con informazioni utili come: UserId ecc.  Questo approccio separa meglio la logica dell'applicazione

void banUser(int userId){
      DomainEvents.Raise<UserBanAttemptedEvent>(new UserBanAttemptedPayload())

      User user= UserRepository.getUserById(userId);
      user.ban();
      UserRepository.update(user);

      DomainEvents.Raise<UserBannedEvent>(new UserBannedPayload())
}

Ci sono molte implementazioni di questi pattern, esempi:

link

DDDSample.Net

    
risposta data 04.12.2014 - 20:19
fonte