È una domanda interessante che sembra emergere in varie forme.
Sono dell'opinione che l'approccio migliore sia quello di consentire il concetto di un oggetto che è uno stato non valido.
Il motivo è che le regole di convalida per un oggetto non sono solitamente impostate in pietra. Possono cambiare nel tempo o essere diversi per le diverse operazioni. Quindi un oggetto che hai creato, popolato e persistito qualche tempo fa, ora può essere considerato non valido.
Se hai i controlli di convalida del setter o del costruttore, allora hai un grosso problema nel fatto che la tua applicazione commetterà un errore quando tenti di recuperare queste entità dal tuo database, o rielaborare i vecchi input ecc.
Inoltre, non penso che le regole aziendali incorporino la semplice convalida sì / no per la maggior parte. Se il tuo dominio sta vendendo torte e non consegni il sud del fiume, ma qualcuno ti offre un milione di sterline per farlo. Quindi fai un'eccezione speciale.
Se stai elaborando milioni di applicazioni e hai regole severe su cosa possono essere i caratteri in un campo, probabilmente hai un processo per correggere campi danneggiati. Non vuoi affatto essere in grado di accettare un campo errato, ma segue semplicemente un percorso diverso attraverso il Dominio.
Quindi, se nel codice sei così rigido che i dati "non validi" non possono mai esistere perché il costruttore genererebbe un'eccezione, sei destinato a essere fragile e fallire per domande come "quante persone hanno compilato il modulo in modo errato ? "
Consenti i dati e fallisci l'operazione. In questo modo puoi modificare i dati o le regole per l'operazione e riutilizzarla.
Esempio:
public class Order
{
public string Id {get;set;}
public string Address {get;set;}
public void Deliver()
{
//check address is valid for delivery
if(String.IsNullOrWhiteSpace(this.Address))
{
throw new Exception("Address not supplied");
}
//delivery code
}
}
Quindi qui non siamo in grado o non vogliamo consegnare a indirizzi vuoti. L'ordine dell'oggetto dominio consente di compilare un indirizzo vuoto ma genera un'eccezione se si tenta di consegnare tale ordine.
Un'applicazione, ad esempio un addetto alla coda che elabora gli ordini dai dati json archiviati in una coda, imbattendosi in un ordine "non valido":
{
"Address" :""
}
È in grado di creare l'oggetto Ordine, poiché non ci sono controlli di convalida nel costruttore o il settatore per Indirizzo. Tuttavia, quando viene chiamato il metodo Deliver, verrà generata l'eccezione e l'applicazione sarà in grado di eseguire un'azione. ad esempio
public class QueueWorker
{
public void ProcessOrder(Order o)
{
try
{
o.Deliver();
}
catch(Exception ex)
{
Logger.Log("unable to deliver order:${o.Id} error:${ex.Message}");
MoveOrderToErrorQueue(o);
}
}
}
L'applicazione può ancora funzionare con l'ordine invalido, spostandolo nella coda degli errori, accedendo al proprio ID, segnalando errori, ecc. Ma l'operazione di consegna contiene la logica del dominio di come si desidera gestire la consegna agli indirizzi vuoti.
Se la logica del dominio successivamente cambia con ulteriori requisiti:
public class Order
{
public string Id {get;set;}
public string Address {get;set;}
public void Deliver()
{
//check address is valid for delivery
if(String.IsNullOrWhiteSpace(this.Address))
{
throw new Exception("Address not supplied");
}
if(Address.Contains("UK"))
{
throw new Exception("UK orders not allowed!");
}
//delivery code
}
}
Quindi puoi ancora elaborare gli ordini sulla coda che sono stati generati quando gli indirizzi del Regno Unito sono stati autorizzati e ottenere il risultato previsto.
È interessante confrontare la mia risposta con quella di @VoiceOfUnReason.
Ho usato un indirizzo stringa per semplicità e anche perché non esiste una definizione assoluta di cosa sia un indirizzo. Ma se abbiamo una definizione più assoluta, diciamo che il suo deposito ha sempre una valuta. È assurdo parlare di un deposito senza valuta.
In questo caso sì, puoi definire un nuovo tipo di valore che semplicemente non può esistere a meno che tu non abbia specificato la valuta e il carico di potenziali errori nel tuo codice semplicemente non sia possibile.
Ma devi essere sicuro che sia una cosa fondamentale. Altrimenti stai chiedendo guai in seguito!