Un servizio di dominio può anche essere una fabbrica?

0

Sto creando un servizio di dominio per ciascuna delle mie radici aggregate al fine di facilitare alcune logiche che non saranno in grado di adattarsi all'entità stessa. Preferisco non implementare una fabbrica e un servizio per ogni radice aggregata.

Inoltre, non voglio esporre direttamente i miei repository ai servizi applicativi. I miei repository avranno un IQueryable esposto. I servizi nasconderanno questo dal livello dell'applicazione definendo la query e restituendo risultati paginati.

Vedi un anti-pattern con l'implementazione di un servizio di dominio come fabbrica?

public class AdministrationAccountService
{
    private readonly ISecurityUnitOfWork unitOfWork;
    private readonly IDomainEventDispatcher dispatcher;

    public AdministrationAccountService(
            ISecurityUnitOfWork unitOfWork, 
            IDomainEventDispatcher dispatcher
    ) {
        this.unitOfWork = unitOfWork;
        this.dispatcher = dispatcher;
    }

    public AdministrationAccount Lookup(string username)
    {
        var account = unitOfWork.AdministrationAccountRepository.GetByUsername(username);
        dispatcher.RaiseAsync(new AccountRecordOpenedEvent(account));
        return account;
    }

    public AdministrationAccount RegisterNewAccount(string username, string displayName)
    {
        var account = new AdministrationAccount(username, displayName);
        unitOfWork.AdministrationAccountRepository.Add(account);
        unitOfWork.Commit();
        return account;
    }
}
    
posta Todd Skelton 27.03.2018 - 19:41
fonte

1 risposta

2

Iniziamo con una breve discussione su cosa sia Domain Service e perché dovresti usarne uno. Perché esiterei, dopo un'ispezione iniziale, a chiamare il tuo esempio a Domain Service .

Domain Services viene spesso utilizzato per risolvere due problemi: quando si desidera estrarre una sorta di calcolo o altro processo privo di effetti collaterali in un proprio oggetto da utilizzare / riutilizzare da molti pezzi del proprio dominio, o quando esiste una logica di business sul comportamento di un processo che naturalmente si estende su più Entities . Il primo ha molte manifestazioni ovvie, ma l'esempio per eccellenza di quest'ultimo è per il coordinamento delle transazioni che avvengono tra Entities . Cioè, l'esecuzione del processo di business richiede l'esecuzione di comandi a più di un Entity .

Supponiamo che tu abbia un Atm e un CheckingAccount . Ritirare denaro da Atm richiede la conoscenza che CheckingAccount ha fondi sufficienti per completare la transazione. Poiché Atm.WithdrawCurrency( decimal amount ) è completamente separato da CheckingAccount.Debit( decimal amount ) , ma entrambi devono essere coordinati per completare la transazione, un Domain Service è una soluzione apt. In questo caso, il AtmService terrà la conoscenza riguardo al fatto se distribuiremo denaro o meno.

A parte le considerazioni precedenti, Domain Services servirà solo a rendere il tuo modello più anemico. Può essere incredibilmente allettante abbattere tutto il comportamento del tuo sistema in "servizi" discreti che semplicemente agiscono sul tuo modello, ma questa è l'antitesi del DDD e fa solo male a lungo andare.

Osservando il tuo esempio, contiene la logica di business (arriveremo a quel Event in un momento)? Non proprio. I tuoi metodi sembrano semplicemente coordinarsi tra il tuo Entities e il mondo esterno. Non ci sono davvero decisioni prese. Questo è più simile a Application Service (recupera pezzo di modello - > comando di esecuzione - > save).

Per quanto riguarda Event , eviterei di aumentare Events da Application Service . Se, per qualche motivo, ti occorre una registrazione Event quando AdministrationAccount è "aperto", prova a renderlo più esplicito:

// AdministrationAccount
public void Open() 
{
    this.state = this.state.Open(this);
}

quindi nel suo stato:

// ClosedAdministractionAccountState
public IAdministrationAccountState Open( AdministrationAccount account )
{
    DomainEvents.RaiseAsync(new AccountRecordOpenedEvent(this));

    return new OpenedAdministrationAccountState(account);
}

L'esempio precedente utilizza un FSM, ma qui potrei concepire altre opzioni. L'importante è che la logica e Event siano esattamente all'interno del tuo dominio a cui appartengono. Non fluttuare in qualche metodo di Service in cui saranno inevitabilmente ignorati.

Come per il tuo altro metodo RegisterNewAccount . È davvero il posto giusto per creare l'account? Quando parli di un nuovo account che viene aperto in ufficio, dici "Il AdministrationAccountService ha registrato un nuovo account con username e displayName "? Oppure dici "Un AdminUser ha registrato un nuovo account"? Quello che sto ottenendo qui è che il metodo potrebbe facilmente essere refactored per far parte di ciò che è sempre in possesso di username e displayName prima della registrazione. Per esempio. %codice%. Gli account (e le loro informazioni) non vengono fuori dal nulla. Puoi controllare questo link per un po 'di più: link

Refactoring verso i precedenti aiuta a purificare e distillare il tuo servizio applicativo.

Per quanto riguarda se una AdminUser.Register() può anche essere una fabbrica? Direi, in generale, no. È concepibile? Certo, ma starai meglio a rifocalizzare il tuo modello verso una visione più profonda in modo che non sia necessario. Questo tipo di domanda è quasi sempre un segno di un modello carente. Non alcuni dettagli tecnici mancanti.

    
risposta data 31.03.2018 - 01:00
fonte

Leggi altre domande sui tag