Convalida all'interno di Constructor

4

Ho appena letto il seguente post di blog: Validazione e DDD Di Vladimir Khorikov .

Il blog parla dell'utilizzo dei seguenti modelli per la convalida di un oggetto entità:

  1. Metodo IsValid
  2. Verifica validità nel livello dei servizi applicativi
  3. TryExecute pattern
  4. Esegui / CanExecute pattern

Vedi il codice qui sotto:

public Person(AbstractValidator<Applicant> validator, IRulesOfferCalculator rulesOfferCalculator, int iD,
            string name, DateTime dateOfBirth, string Address)
        {
            _iD = iD;
            _name = name;
            _dateOfBirth = dateOfBirth;
            _Address = Address;
            _validator = validator;
            _rulesOfferCalculator = rulesOfferCalculator;
            _validator.ValidateAndThrow(this);
        }

Si noti che la convalida viene eseguita all'interno del costruttore qui. Perché questa non è un'opzione? Si tratta di un modello anti?

Si noti che sto chiedendo specificamente nel contesto di un modello di dominio ricco. Sto usando Fluent Validation piuttosto che gli attributi.

    
posta w0051977 27.06.2017 - 12:44
fonte

1 risposta

7

Is this an anti pattern?

Vedo due anti-pattern qui

  1. passare attorno ai riferimenti agli oggetti prima che la loro inizializzazione sia completa è un'idea cattiva .
  2. utilizzare un validatore astratto per eseguire il controllo suggerisce che non stai rispettando il principio di coesione.

Più in generale, penso che ci sia un po 'di confusione nel saggio di Khorikov: non convalidiamo le entità, convalidiamo lo stato . L'entità è solo un'identità che progredisce da uno stato all'altro.

Perulterioriinformazionisuquestopunto,vedi il discorso 2011 di Stuart Halloway .

Lo stato che stai convalidando è un oggetto valore, nella lingua di Evans.

Lanciare un ArgumentException nel costruttore quando lo stato che ti è stato dato non soddisfa il tuo invariant è perfettamente cosa ragionevole da fare.

Ma ancora non inietterei un validatore per fare il controllo dello stato - sembra che stiamo trattando l'entità come un muto sacchetto di stato, con tutto lo stato che vive altrove. Confrontati con la discussione di Martin Fowler sui modelli di dominio anemici , e vedrai cosa intendo.

Would you suggest something like: Execute / CanExecute pattern for the validation?

Non sono un fan; ma il ragionamento è un po 'complicato.

public IReadOnlyList<string> CanDeliver(string address, DateTime time)

Quindi la prima cosa da notare è che questa è una query, il che significa che dovrebbe essere sicuro ; non induce una mutazione nell'entità.

Ciò che distingue questa query dall'essere una funzione completa è lo stato corrente dell'entità. Vale a dire, CanDeliver è applicazione parziale , con una variabile implicita legata allo stato corrente (immutabile). Quindi rendiamo esplicito il bind:

public IReadOnlyList<string> CanDeliver(Order.State currentState, string address, DateTime time)

Si noti che l'entità ora scompare, cioè la legge di Demetra ci dice che CanDeliver appartiene allo stato , non all'entità .

In questo caso, puoi chiamare State.CanDeliver in qualsiasi momento, nel controller o persino nel client durante la composizione della richiesta. Ma come sottolinea David Arno , hai ancora la gara, motivo per cui Khorikov ha ancora bisogno del controllo.

I have also injected RulesOfferCalculator into this class. What do you think of that?

Iniettare comportamenti di dominio in un'entità è strano, e probabilmente la mia ipotesi è sbagliata nella maggior parte dei casi.

Verifica la definizione di SERVICE in Domain Driven Design

  1. L'operazione si riferisce a un concetto di dominio che non è una parte naturale di un'ENTITÀ o di un VALORE DI OGGETTO
  2. L'interfaccia è definita in termini di altri elementi del modello di dominio
  3. L'operazione è senza stato

In casi comuni, un servizio di dominio viene passato a un'entità come argomento, anziché incorporato nell'entità come se fosse un pezzo di stato.

    
risposta data 27.06.2017 - 14:57
fonte

Leggi altre domande sui tag