2015-04-14 7 views
15

Diciamo che abbiamo decine di POJO java che rappresentano il mio dominio, cioè i miei dati nel sistema che scorre come oggetti tra diversi livelli del mio sistema. Il sistema può essere un'applicazione Web o una semplice applicazione desktop. Ciò che il dominio consiste non ha molta importanza.Il POJO Java deve avere la convalida del campo e generare eccezioni nei metodi setter?

Durante la progettazione del mio sistema, sono confuso dove dovrei inserire qualsiasi logica di validazione. I miei POJO (oggetti di dominio) rappresentano i miei dati, e alcuni dei campi all'interno di quegli oggetti devono aderire a determinati criteri, ma se inserisco molta logica di validazione nei miei metodi setter, allora l'unico modo per dire al client chiamante è gettare un'eccezione E se non voglio che il sistema si blocchi, l'eccezione deve essere un'eccezione controllata che deve essere catturata e gestita. La conseguenza di ciò è che ogni volta che creo un nuovo oggetto usando i metodi setter (o anche i costruttori), ho fatto o rilanciare quell'eccezione o usare il blocco try-catch. Non sembra giusto essere obbligati a usare il try-catch su molti metodi setter.

Quindi la domanda è dove dovrei mettere la mia logica di validazione, in modo da non ingombrare il mio codice con un sacco di blocchi try-catch e rethrows. I migliori mangiatori di byte di JAVA sono invitati a partecipare alla discussione.

Ho cercato e cercato su Google, ma non ho trovato alcuna discussione specifica su questo argomento, quindi aspetto con grande entusiasmo di avere una visione più profonda di come le cose dovrebbero essere fatte davvero.

+0

hai controllato la convalida del bean Java http://docs.oracle.com/javaee/6/tutorial/doc/gircz.html? –

+0

Prova a utilizzare la convalida del bean ([JSR-303] (http://beanvalidation.org/1.0/spec/)), come implementato da ['hibernate-validator'] (http://hibernate.org/validator/) – beerbajay

+0

Sì, ho controllato questi concetti, ma non sto chiedendo particolari API o metodi. Voglio capire e riflettere su cosa dovrebbe essere fatto con la convalida dei dati, e dove la validazione dovrebbe essere fatta per non ingombrare il sistema ovunque con un sacco di eccezioni e gestione delle eccezioni. – Moni

risposta

13

Potreste aver risposto alla tua domanda quando hai detto

alcuni dei campi all'interno di quegli oggetti devono rispettare determinati criteri

Aiuta sempre pensare alle invarianti in il tuo sistema, cioè le cose che vuoi mantenere a tutti i costi o le regole che devono essere sempre seguite.
I tuoi POJO sono "l'ultima linea di difesa" per tali invarianti sui tuoi oggetti di dati e quindi un luogo appropriato, o persino necessario, per mettere la logica di convalida. Senza tale convalida, un oggetto potrebbe non rappresentare più qualcosa che ha senso nel tuo dominio.

Questi invarianti di sistema formano un contratto tra gli oggetti (oi metodi) ei loro "clienti". Se qualcuno sta cercando di usarli contrariamente al contratto (auspicabile ben documentato), lanciare un'eccezione è la cosa giusta da fare, poiché è responsabilità del cliente utilizzare correttamente le singole parti del sistema.

Nel corso del tempo, ho iniziato favorendo incontrollati eccezioni rispetto a quelli controllati per eventuali casi di violazione di contratto, in parte a causa del motivo si parla, vale a dire per evitare try - catch blocchi ovunque.eccezioni unchecked standard di
di Java includono:

  • NullPointerException
  • IllegalArgumentException
  • IllegalStateException
  • UnsupportedOperationException

Una guida di miglior pratica è quella di utilizzare eccezioni controllate quando un errore è considerato recuperare in grado e eccezioni non selezionate in caso contrario.

capitolo 9 di Joshua Bloch di "Effective Java, 2nd ed." fornisce più saggezza su questo argomento:

  • Articolo 57: utilizzare le eccezioni solo per le condizioni eccezionali
  • Articolo 58: Uso controllato eccezioni per le condizioni recuperabili ed eccezioni runtime per errori di programmazione
  • Articolo 59: Evitare l'uso non necessario di eccezioni controllate
  • Articolo 60: favorire l'utilizzo di eccezioni standard

Nessuno dei precedenti deve scoraggiare l'utilizzo di qualsiasi logica di convalida appropriata a livelli superiori, in particolare per applicare regole o vincoli aziendali specifici del contesto.

+0

Sì, il POJO deve essere sempre in uno stato valido. Ho esaminato gli elementi di Java efficace ma sono poco difficili da comprendere, penso che sicuramente sembreranno difficili per un intermediario che conosce i principi del design OO, ma non può decidere correttamente come applicare questi elementi. Ad esempio, non capisco cosa intenda in particolare con "recuperabili" e "errori di programmazione". Alcuni esempi concreti e probabilmente diversi potrebbero aiutare a capire le potenti idee dietro quei suggerimenti. Che cosa intende con "inutili", abbiamo esempi ben noti di ciò. – Moni

+0

Sono d'accordo sul fatto che Bloch richiede una lettura attenta e le vostre preoccupazioni sarebbero grandi domande SO da sole. Un errore _programming_ è qualcosa che viola un contratto, ad es. passando 'null', o un indice negativo, quando è documentato che questo non è supportato.Un esempio di errore _recoverable_ potrebbe essere qualcosa di simile a un timeout, in cui il chiamante potrebbe decidere di riprovare più tardi o semplicemente di rinunciare; l'utilizzo di un'eccezione _checked_ costringe il chiamante a gestire questa situazione e a prendere una decisione. L'utilizzo delle eccezioni controllate per il controllo del flusso invece dei blocchi 'IF-ELSE' è un esempio di _uso necessario. – fspinnenhirn

3

Tutto sommato, inoltre, non credo che esista una soluzione unica per soddisfare ogni esigenza, e si riduce al proprio scenario e alle proprie preferenze.

Dal punto di vista dell'incapsulamento, credo che la convalida del setter sia la giusta via da seguire poiché è il luogo logico dove decidere se le informazioni fornite sono corrette e offrire una spiegazione dettagliata su ciò che potrebbe essere sbagliato. Comunque io non sono sicuro di cosa si intende per:

e se io non voglio che il sistema di crash, l'eccezione deve essere un eccezione controllata ...

Perché il crash del sistema ? Le eccezioni non controllate possono essere catturate molto bene come quelle controllate. Devi capire come dovrebbe comportarsi il tuo programma quando si verifica un evento del genere, così puoi decidere dove prenderli e cosa fare.

Selezionato contro deselezionato è stato a lungo, ed è ancora, dibattuto in vari modi e credenze, ma non vedo alcun motivo per cui non si dovrebbe lanciare un'eccezione non controllata. È sufficiente creare un comune ConfigurationException (o utilizzare lo IllegalArgumentException) o qualsiasi altra cosa che fa galleggiare la propria imbarcazione, contrassegnare di conseguenza le firme dei metodi e aggiungere java-doc appropriati, in modo che chiunque li chiami sappia cosa aspettarsi e lo lanci quando richiesto.

A seconda delle relazioni oggettuali e della gerarchia, un'altra soluzione potrebbe essere builders che esegue le convalide personalizzate solo durante la creazione delle istanze. Ma come ho detto dipende molto dallo scenario, e potresti non essere in grado di impedire ad altre persone di istanziare manualmente e inserire in modo errato alcuni oggetti.

+0

Concordato sul pattern Builder (+1), questo è ciò a cui ho pensato quando ho letto la domanda. –

1

In alcune situazioni la soluzione è rendere privati ​​tutti i setter e fornire un singolo punto di ingresso per inizializzare gli oggetti.Quindi tutta la gestione della validazione e delle eccezioni si trova in quel metodo di inizializzazione.
Ciò garantisce anche che nessun oggetto possa essere parzialmente inizializzato.
La modifica dello stato dell'oggetto può essere gestita anche in questo modo, rendendo l'oggetto immutabile tranne attraverso un metodo di costruzione/inizializzazione, questo può diventare uno spreco se abusato.

1

Mentre è possibile inserire la logica di convalida sui metodi di settaggio dei bean, ho scoperto che in pratica una separazione più chiara delle preoccupazioni sarebbe spostare qualsiasi convalida complessa in un'altra classe specifica per la convalida. Ascoltami.

L'uso della convalida del bean è soddisfacente, ma in molti casi (a cui sono sicuro che vi state imbattendo ora), una semplice annotazione non porterà una convalida sufficientemente approfondita. I framework come Spring hanno Validator s che è possibile implementare per fare ciò.

Ci sono numerosi vantaggi per la separazione logica di convalida:

  • riutilizzo del codice. In alcuni casi, la convalida setter per un bean può essere identica a quella di un altro bean. Ciò porta anche a test unitari più concisi.
  • In molti casi, non avrà a che fare con le eccezioni a tutti, ma piuttosto la visualizzazione di un messaggio di errore per l'utente
  • È possibile accedere in modo appropriato senza riempire i tuoi POJO con le dichiarazioni di registrazione o costringendoli a implementare un logger
  • Il codice è molto più leggibile e l'intendimento è compreso meglio

Spero che questo aiuti.

+0

Alcuni punti essenziali che state facendo qui, specialmente la registrazione, la leggibilità e la separazione delle preoccupazioni. Riuscirai a cucinare un esempio davvero "profondo" e realistico che chiarisca un po 'il fumo? – Moni

+0

Se in qualche modo avete bisogno di un esempio più specifico, posso fornirne uno in seguito, ma questo dovrebbe essere sufficiente: http://www.journaldev.com/2668/spring-mvc-form-validation-example-using-annotation-and-custom- validatore-implementazione. Come puoi vedere, non c'è alcuna validazione nei metodi setter. Questo design è stato utilizzato da molto tempo e negli ambienti di produzione. Nel caso in cui il collegamento venga interrotto in un secondo momento, Googling per gli usi di esempio di Spring Validator ti darà più casi. – bphilipnyc

Problemi correlati