Verifica dei parametri in Costruttore o Servizio

4

Leggevo su questa pagina su quando per controllare i parametri durante la costruzione di un oggetto. La risposta accettata suggerisce di lanciare l'eccezione dal costruttore in modo che un oggetto non valido non possa essere costruito.

Sono d'accordo con questo approccio e non riesco a vedere come si possa costruire un Person senza name .

Tuttavia, uno dei commenti suggerito:

I also agree that second option is better because it is more reusable than the first one. The first option is violating Object Oriented Principles. Even the factory method is better designed than that.

Domande:

  1. Esattamente quali principi OOP vengono violati quando si genera un'eccezione nel costruttore? È la linea guida che un costruttore non dovrebbe fare il lavoro?

  2. L'altro approccio suggerito dall'OP era un PersonService , tuttavia questa è solo una speculazione, ma con questo approccio speri che il codice client chiamerà public void addPerson(Person personToAdd) per verificare che l'oggetto persona non lo faccia t contenere un nullo? Cosa succede se trovano un modo per aggirare quell'assegno? Oppure prima di public void addPerson(Person personToAdd) usano quell'oggetto in un'altra classe non scritta da loro che si aspetta un oggetto Person valido?

Ancora una volta, tutto questo fa parte della speculazione, ma sembra che tu stia mettendo molta responsabilità sul client per garantire che l'oggetto Person sia valido quando avrebbe dovuto essere fatto al momento della sua creazione.

    
posta Adam 18.09.2018 - 17:53
fonte

2 risposte

1

1) Nessun principio OOP è rotto quando si lancia una eccezione in un costruttore .

Bjarne Stroustrup ha ricordato nel suo libro La progettazione e l'evoluzione di C ++ come sono state progettate eccezioni nel linguaggio tra il 1984 e il 1989 in collaborazione con esperti di diverse società come IBM e Sun:

To some, one of the most important spect of exceptions is that they provide a general mechanism for reporting errors detected in constructors

Questo vale anche per Java e altri linguaggi OO.

2) L'utilizzo di un servizio per creare oggetti è anche un approccio valido: non è raro utilizzare builder o fabbriche per creare oggetti.

Le fabbriche possono consentire di gestire gli errori in modo diverso rispetto al lancio di eccezioni e, in particolare, per controllare la coerenza dei parametri prima della costruzione.

Tuttavia, non è sempre consigliabile utilizzare questo tipo di servizi nella parte superiore di un costruttore.

Inoltre, non è possibile anticipare tutti gli errori. Supponiamo che durante la creazione si verifichi un evento inaspettato non correlato ai parametri. Ad esempio, non è rimasto abbastanza memoria per creare un oggetto grande, o alcune risorse sono state controllate ma non possono essere allocate (specialmente nel contesto RAII).

3) Tuttavia, non abusare delle eccezioni

L'eccezione non è un sostituto per la convalida dei parametri. Il principio più importante con eccezione è che dovrebbero sparare solo per situazioni eccezionali. Se un parametro errato è una situazione comune o se ti aspetti che una costruzione su tre possa causare un'eccezione, dovresti davvero mettere in discussione il tuo progetto e ridistribuirlo per ridurre il rischio.

Se lo usi per la programmazione difensiva, supponendo che il nome debba essere controllato prima, ma fornisci questa escrezione come rete di sicurezza, allora va bene.

    
risposta data 19.09.2018 - 08:45
fonte
0
  1. L'unico principio che posso vedere essere violato è Encapsulation, poiché l'eccezione generata sta per esporre una struttura interna dell'oggetto. Se l'oggetto non è esposto pubblicamente, ciò potrebbe non essere motivo di preoccupazione. Storicamente, quando un oggetto falliva parzialmente attraverso la costruzione, potrebbe essere necessario ripulire tutte le risorse allocate a quel punto. I netturbini hanno minimizzato (ma non eliminato) questo impatto. Nota anche che chiamare un Costruttore accoppia esplicitamente il tuo codice alla firma del Costruttore. Questo è in gran parte banale, ma potrebbe richiedere una rilettura se la firma cambia, come può accadere quando si passa a versioni più recenti delle proprie dipendenze.
  2. meh? Questo non ha molto senso per me.

Il pattern favorito corrente (IMO) per la costruzione pulita di un oggetto è il pattern Builder . Tra i vantaggi del Builder c'è la possibilità di convalidare i parametri prima che vengano passati al Costruttore. Questa convalida può verificarsi quando viene impostato il parametro specifico o durante l'invocazione build() . La convalida nella chiamata param() può fungere da Circuit Breaker , non riuscire velocemente e potenzialmente eliminare il lavoro per ottenere altri valori param prima il loro uso; ex.

...size(5).foo(getMassivelyComplexObject()).build

Se 5 non è un size valido e la convalida è implementata nella chiamata size() , hai evitato il lavoro richiesto per ottenere il valore per foo() .

Nel caso in cui la firma di un Costruttore cambi, i Builder ti isolano in due modi:

  1. Le chiamate di builder param() di solito sono indipendenti dall'ordine.
  2. Le chiamate individuali del Builder param() sono facoltative se il Builder fornisce i valori predefiniti per il parametro specifico.

Anche il Pattern Builder ha molte altre qualità, ma la tua domanda riguarda Failure durante la costruzione, quindi mi fermerò qui.

    
risposta data 19.09.2018 - 08:31
fonte