Troppi parametri nei metodi Java, parte 2: oggetto Parametri

Nel mio post precedente, ho esaminato alcuni dei problemi associati a lunghi elenchi di parametri per metodi e costruttori. In quel post, ho discusso la sostituzione di primitive e tipi incorporati con tipi personalizzati per migliorare la leggibilità e l'indipendenza dai tipi. Questo approccio ha reso più leggibili i numerosi parametri di un metodo o di un costruttore, ma non ha fatto nulla per ridurre il numero di parametri. In questo post, esamino l'uso di un oggetto parametro per ridurre il numero di parametri a un metodo o un costruttore.

Generalmente non è una buona idea creare oggetti "junk drawer" che accoppiano parametri non correlati la cui unica relazione tra loro è che devono essere passati allo stesso metodo o costruttore. Tuttavia, quando i parametri correlati vengono passati a un costruttore o metodo come parte di un oggetto altamente coeso , il refactoring noto come Introduce Parameter Object è una buona soluzione. L'utilizzo di questo refactoring è descritto come "gruppo [ing] di parametri che naturalmente vanno insieme". Dimostrerò questo refactoring in questo post.

Per dimostrare l'utilità del refactoring di Introduce Parameter Object, diamo prima un'occhiata all'esempio dell'ultimo post che utilizza numerosi parametri Stringe booleanin una chiamata al metodo.

 /** * Instantiate a Person object. * * @param lastName * @param firstName * @param middleName * @param salutation * @param suffix * @param streetAddress * @param city * @param state * @param isFemale * @param isEmployed * @param isHomeOwner * @return */ public Person createPerson( final String lastName, final String firstName, final String middleName, final String salutation, final String suffix, final String streetAddress, final String city, final String state, final boolean isFemale, final boolean isEmployed, final boolean isHomeOwner) { // implementation goes here } 

Come ho discusso nel post precedente, questo approccio è noioso per i chiamanti, rende fin troppo facile passare i parametri nell'ordine sbagliato con poca sicurezza dei tipi e può ridurre la leggibilità del codice. Fortunatamente, i parametri in questo esempio forniscono alcune buone opportunità per applicare il refactoring di Introduce Parameter Object. I parametri "nomi" (inclusi saluto e suffisso) potrebbero essere inclusi in una singola classe di nome completo. I parametri dell'indirizzo (indirizzo, città e stato) potrebbero essere in un unico oggetto indirizzo. Gli altri parametri potrebbero non essere raggruppati così facilmente in un'unica classe con elevata coesione.

Con le applicazioni suggerite del refactoring di Introduce Parameter Object, la chiamata al metodo mostrata in precedenza è più semplice grazie al numero ridotto di parametri. Questo è mostrato nel prossimo listato di codice.

 public Person createPerson( final FullName fullName, final Address address, final boolean isFemale, final boolean isEmployed, final boolean isHomeOwner) { return new Person(); } 

L'esempio precedente ora ha solo cinque parametri ed è più leggibile e più facile da usare dai client. È anche più sicuro dal punto di vista della digitazione poiché in questo caso è quasi impossibile confondere stringhe di nomi con stringhe di indirizzo. Sfortunatamente, i tre parametri booleani rimangono un po 'fonte di potenziale confusione e leggibilità del cloud. Gli elenchi di codice successivi mostrano potenziali implementazioni delle classi FullNamee Address.

FullName.java (semplice)

package dustin.examples; /** * Full name of a person. * * @author Dustin */ public final class FullName { private final String lastName; private final String firstName; private final String middleName; private final String salutation; private final String suffix; public FullName( final String newLastName, final String newFirstName, final String newMiddleName, final String newSalutation, final String newSuffix) { this.lastName = newLastName; this.firstName = newFirstName; this.middleName = newMiddleName; this.salutation = newSalutation; this.suffix = newSuffix; } public String getLastName() { return this.lastName; } public String getFirstName() { return this.firstName; } public String getMiddleName() { return this.middleName; } public String getSalutation() { return this.salutation; } public String getSuffix() { return this.suffix; } @Override public String toString() { return this.salutation + " " + this.firstName + " " + this.middleName + this.lastName + ", " + this.suffix; } } 

Address.java (semplice)

package dustin.examples; /** * Representation of a United States address. * * @author Dustin */ public final class Address { private final String streetAddress; private final String city; private final String state; public Address(final String newStreetAddress, final String newCity, final String newState) { this.streetAddress = newStreetAddress; this.city = newCity; this.state = newState; } public String getStreetAddress() { return this.streetAddress; } public String getCity() { return this.city; } public String getState() { return this.state; } @Override public String toString() { return this.streetAddress + ", " + this.city + ", " + this.state; } } 

Sebbene il codice sia migliorato, ci sono ancora alcuni problemi che possono essere migliorati. In particolare, il metodo originale con troppi parametri ha ancora tre booleanparametri che possono essere facilmente confusi tra loro. Sebbene i Stringparametri di quel metodo siano stati scomposti in due nuove classi, queste due nuove classi consistono ancora ciascuna in un gruppo di Strings. In questi casi, si potrebbe desiderare di integrare il refactoring di Introduce Parameter Object con l'uso di tipi personalizzati. Usando i tipi personalizzati che ho mostrato nel mio ultimo post, il metodo con troppi parametri ora assomiglia a quello mostrato nel prossimo listato di codice.

 public Person createPerson( final FullName fullName, final Address address, final Gender gender, final EmploymentStatus employment, final HomeownerStatus homeownerStatus) { // implementation goes here } 

Il metodo ora ha meno parametri e i parametri che ha sono tutti di tipi distinti. Gli IDE e il compilatore Java possono ora essere particolarmente utili per garantire che i client utilizzino correttamente questa interfaccia. L'applicazione di tipi personalizzati (scritti nell'ultimo post) alle classi FullNamee Addressrisulta nei prossimi due nuovi elenchi di codice per quelle classi.

FullName.java (tipi personalizzati)

package dustin.examples; /** * Full name of a person. * * @author Dustin */ public final class FullName { private final Name lastName; private final Name firstName; private final Name middleName; private final Salutation salutation; private final Suffix suffix; public FullName( final Name newLastName, final Name newFirstName, final Name newMiddleName, final Salutation newSalutation, final Suffix newSuffix) { this.lastName = newLastName; this.firstName = newFirstName; this.middleName = newMiddleName; this.salutation = newSalutation; this.suffix = newSuffix; } public Name getLastName() { return this.lastName; } public Name getFirstName() { return this.firstName; } public Name getMiddleName() { return this.middleName; } public Salutation getSalutation() { return this.salutation; } public Suffix getSuffix() { return this.suffix; } @Override public String toString() { return this.salutation + " " + this.firstName + " " + this.middleName + this.lastName + ", " + this.suffix; } } 

Address.java (tipi personalizzati)

package dustin.examples; /** * Representation of a United States address. * * @author Dustin */ public final class Address { private final StreetAddress streetAddress; private final City city; private final State state; public Address(final StreetAddress newStreetAddress, final City newCity, final State newState) { this.streetAddress = newStreetAddress; this.city = newCity; this.state = newState; } public StreetAddress getStreetAddress() { return this.streetAddress; } public City getCity() { return this.city; } public State getState() { return this.state; } @Override public String toString() { return this.streetAddress + ", " + this.city + ", " + this.state; } } 

Tutti i miei esempi finora sono stati di publicclassi autonome . Trovo spesso che se ho bisogno di un oggetto parametro semplicemente per passare informazioni tra metodi e costruttori nello stesso pacchetto, può essere utile rendere queste classi di oggetti parametro packageambito. In alcuni casi è possibile utilizzare anche classi annidate per questi oggetti parametro.

Benefici e vantaggi

Il vantaggio più ovvio dell'oggetto parametro è la riduzione del numero di parametri passati a un metodo o un costruttore. Questo incapsulamento dei parametri correlati rende più facile accertare rapidamente quali tipi vengono passati al metodo o al costruttore. È più facile per uno sviluppatore comprendere un numero inferiore di parametri.

Gli oggetti parametro condividono uno degli stessi vantaggi forniti dai tipi personalizzati: la possibilità di aggiungere comportamenti e caratteristiche aggiuntivi all'oggetto parametro per funzioni di comodità. Ad esempio, avere una Addressclasse piuttosto che un gruppo di Stringtipi consente di convalidare gli indirizzi.

Costi e svantaggi

Lo svantaggio principale dell'oggetto parametro è un piccolo lavoro extra per progettare, implementare e testare la classe. Tuttavia, questi sono abbastanza facili da scrivere e testare e strumenti moderni come IDE e linguaggi di scripting rendono ancora più facile automatizzare le parti più banali e noiose di queste attività. Un argomento ancora più piccolo contro questo approccio è che può essere abusato. Se uno sviluppatore inizia a raggruppare parametri non correlati in una classe solo per ridurre il numero di parametri, ciò non aiuta necessariamente la situazione. Tale approccio riduce effettivamente il numero di parametri, ma l'obiettivo finale di migliorare la leggibilità non è stato raggiunto e si potrebbe sostenere che questo approccio è ancora meno leggibile.

Conclusione

Gli oggetti parametro forniscono un approccio pulito e piacevole per incapsulare in modo appropriato i parametri correlati per ridurre il conteggio totale dei parametri a un metodo o un costruttore. Sono facili da implementare e possono migliorare in modo significativo la leggibilità e i parametri di sicurezza dei tipi passati alle chiamate al metodo e al costruttore. Gli oggetti parametro possono essere ulteriormente migliorati attraverso l'uso di tipi personalizzati come spiegato nel mio post precedente.

Pubblicazione originale disponibile su //marxsoftware.blogspot.com/ (Ispirato da eventi effettivi)

Questa storia, "Too Many Parameters in Java Methods, Part 2: Parameters Object" è stata originariamente pubblicata da JavaWorld.