Programmering

For mange parametere i Java-metoder, del 3: Byggmønster

I mine to umiddelbart tidligere innlegg så jeg på å redusere antall parametere som kreves for en konstruktør eller metodeinnkalling via egendefinerte typer og parameterobjekter. I dette innlegget ser jeg på bruk av bygningsmønsteret for å redusere antall parametere som kreves for en konstruktør, med noen diskusjoner om hvordan dette mønsteret til og med kan hjelpe til med ikke-konstruktormetoder som tar for mange parametere.

I den andre utgaven av Effektiv Java introduserer Josh Bloch bruk av byggemønsteret i vare nr. 2 for å håndtere konstruktører som krever for mange parametere. Bloch demonstrerer ikke bare hvordan du bruker Builder, men forklarer det fordeler i forhold til konstruktører som godtar et stort antall parametere. Jeg kommer til disse fordelene på slutten av dette innlegget, men synes det er viktig å påpeke at Bloch har viet et helt element i sin bok til denne praksisen.

For å illustrere fordelene med denne tilnærmingen, bruker jeg følgende eksempel Person klasse. Det har ikke alle metodene jeg vanligvis vil legge til i en slik klasse fordi jeg vil fokusere på konstruksjonen.

Person.java (uten byggmønster)

pakke dustin. eksempler; / ** * Personklasse brukt som en del av for mange parameterdemonstrasjoner. * * @forfatter Dustin * / person i offentlig klasse {privat slutt String etternavn; privat finale Streng fornavn; privat finale String mellomnavn; privat slutt Stringhilsen; privat slutt Streiksuffiks; privat finale String streetAddress; privat finale String city; privat slutt Strengstat; privat final boolsk isFemale; privat slutt boolsk er sysselsatt; privat siste boolske isHomewOwner; public Person (final String newLastName, final String newFirstName, final String newMiddleName, final String newSalutation, final String newSuffix, final String newStreetAddress, final String newCity, final String newState, final boolean newIsFemale, final boolean newIsEmployed, final boolean. lastName = newLastName; this.firstName = newFirstName; this.middleName = newMiddleName; this.salutation = newSalutation; this.suffix = newSuffix; this.streetAddress = newStreetAddress; this.city = newCity; this.state = newState; this.isFemale = newIsFemale; this.isEm Employed = newIsEm Employed; this.isHomewOwner = newIsHomeOwner; }} 

Denne klassens konstruktør fungerer, men det er vanskelig for klientkoden å bruke riktig. Builder-mønsteret kan brukes til å gjøre konstruktøren enklere å bruke. NetBeans vil refaktorere dette for meg slik jeg har skrevet om tidligere. Et eksempel på den omformede koden vises neste (NetBeans gjør dette ved å opprette alle nye Builder-klasser).

PersonBuilder.java

pakke dustin. eksempler; offentlig klasse PersonBuilder {privat streng newLastName; privat streng newFirstName; privat streng newMiddleName; private String newSalutation; private String newSuffix; private String newStreetAddress; private String newCity; private String newState; private boolske newIsFemale; private boolske newIsEmbled; private boolske newIsHomeOwner; public PersonBuilder () {} public PersonBuilder setNewLastName (String newLastName) {this.newLastName = newLastName; returner dette; } offentlig PersonBuilder setNewFirstName (String newFirstName) {this.newFirstName = newFirstName; returner dette; } public PersonBuilder setNewMiddleName (String newMiddleName) {this.newMiddleName = newMiddleName; returner dette; } offentlig PersonBuilder setNewSalutation (String newSalutation) {this.newSalutation = newSalutation; returner dette; } offentlig PersonBuilder setNewSuffix (String newSuffix) {this.newSuffix = newSuffix; returner dette; } offentlig PersonBuilder setNewStreetAddress (String newStreetAddress) {this.newStreetAddress = newStreetAddress; returner dette; } offentlig PersonBuilder setNewCity (String newCity) {this.newCity = newCity; returner dette; } offentlig PersonBuilder setNewState (String newState) {this.newState = newState; returner dette; } offentlig PersonBuilder setNewIsFemale (boolsk newIsFemale) {this.newIsFemale = newIsFemale; returner dette; } offentlig PersonBuilder setNewIsEm Employed (boolsk newIsEm Employed) {this.newIsEm Employed = newIsEm Employed; returner dette; } public PersonBuilder setNewIsHomeOwner (boolean newIsHomeOwner) {this.newIsHomeOwner = newIsHomeOwner; returner dette; } offentlig person createPerson () {returner ny person (newLastName, newFirstName, newMiddleName, newSalutation, newSuffix, newStreetAddress, newCity, newState, newIsFemale, newIsEm Employed, newIsHomeOwner); }} 

Jeg foretrekker å ha min Builder som en nestet klasse i klassen hvis objekt den bygger, men NetBeans automatiske generering av en frittstående Builder er veldig enkel å bruke. En annen forskjell mellom NetBeans-genererte Builder og Builders som jeg liker å skrive er at de foretrukne Builder-implementeringene mine har påkrevd felt gitt i Builder's konstruktør i stedet for å gi en no-argumenter constructor. Den neste kodelisten viser min Person klasse ovenfra med en Builder lagt til den som en nestet klasse.

Person.java med nestet Person.Builder

pakke dustin. eksempler; / ** * Personklasse brukt som en del av for mange parameterdemonstrasjoner. * * @forfatter Dustin * / offentlig klasse Person {privat slutt String etternavn; privat finale Streng fornavn; privat finale String mellomnavn; privat slutt Stringhilsen; privat slutt Streiksuffiks; privat finale String streetAddress; privat finale String city; privat slutt Strengstat; privat final boolsk isFemale; privat final boolsk er Ansatt; privat siste boolske isHomewOwner; public Person (final String newLastName, final String newFirstName, final String newMiddleName, final String newSalutation, final String newSuffix, final String newStreetAddress, final String newCity, final String newState, final boolean newIsFemale, final boolean newIsEmployed, final boolean. lastName = newLastName; this.firstName = newFirstName; this.middleName = newMiddleName; this.salutation = newSalutation; this.suffix = newSuffix; this.streetAddress = newStreetAddress; this.city = newCity; this.state = newState; this.isFemale = newIsFemale; this.isEm Employed = newIsEm Employed; this.isHomewOwner = newIsHomeOwner; } offentlig statisk klasse PersonBuilder {privat streng nestedLastName; privat streng nestedFirstName; privat streng nestedMiddleName; privat String nestetSalutation; privat streng nestetSuffix; privat streng nestetStreetAddress; private String nestedCity; privat streng nestet stat; privat boolsk nestetIsFemale; private boolske nestedeIsEmbleded; privat boolsk nestetIsHomeOwner; public PersonBuilder (final String newFirstName, final String newCity, final String newState) {this.nestedFirstName = newFirstName; this.nestedCity = newCity; this.nestedState = newState; } offentlig PersonBuilder etternavn (streng newLastName) {this.nestedLastName = newLastName; returner dette; } public PersonBuilder firstName (String newFirstName) {this.nestedFirstName = newFirstName; returner dette; } public PersonBuilder middleName (String newMiddleName) {this.nestedMiddleName = newMiddleName; returner dette; } public PersonBuilder salutation (String newSalutation) {this.nestedSalutation = newSalutation; returner dette; } offentlig PersonBuilder-suffiks (String newSuffix) {this.nestedSuffix = newSuffix; returner dette; } offentlig PersonBuilder streetAddress (String newStreetAddress) {this.nestedStreetAddress = newStreetAddress; returner dette; } public PersonBuilder city (String newCity) {this.nestedCity = newCity; returner dette; } offentlig PersonBuilder-tilstand (String newState) {this.nestedState = newState; returner dette; } offentlig PersonBuilder isFemale (boolsk newIsFemale) {this.nestedIsFemale = newIsFemale; returner dette; } public PersonBuilder isEm Employed (boolean newIsEm Employed) {this.nestedIsEm Employed = newIsEm Employed; returner dette; } public PersonBuilder isHomeOwner (boolean newIsHomeOwner) {this.nestedIsHomeOwner = newIsHomeOwner; returner dette; } offentlig person createPerson () {returner ny person (nestedLastName, nestedFirstName, nestedMiddleName, nestedSalutation, nestedSuffix, nestedStreetAddress, nestedCity, nestedState, nestedIsFemale, nestedIsEmbleded, nestedIsHomeOwner); }}} 

Builder kan være enda finere når den forbedres ved bruk av egendefinerte typer og parameterobjekter som beskrevet i mine to første innlegg om "for mange parametere" -problemet. Dette vises i neste kodeliste.

Person.java med nestet byggmester, egendefinerte typer og parametere

pakke dustin. eksempler; / ** * Personklasse brukt som en del av for mange parameterdemonstrasjoner. * * @forfatter Dustin * / offentlig klasse Person {privat endelig Fullnavn navn; privat sluttadresse adresse; privat slutt Kjønn kjønn; privat slutt EmploymentStatus ansettelse; private final Huseierstatus hjemEierstatus; / ** * Parameterisert konstruktør kan være privat fordi bare den interne byggherren min * trenger å ringe meg for å gi en forekomst til klienter. * * @param newName Navnet på denne personen. * @param newAddress Adresse til denne personen. * @param newGender Kjønn til denne personen. * @param newEm Employment Sysselsettingsstatus for denne personen. * @param newHomeOwner Eierstatus for denne personen. * / privat person (endelig Fullnavn nytt navn, endelig adresse newAddress, endelig Kjønn newGender, endelig EmploymentStatus newEm sysselsetting, endelig HomeownerStatus newHomeOwner) {this.name = newName; this.address = newAddress; this.gender = newGender; dette. arbeidsledighet = ny sysselsetting; this.homeOwnerStatus = newHomeOwner; } offentlig Fullnavn getName () {returner dette.navn; } public Address getAddress () {return this.address; } public Gender getGender () {return this.gender; } offentlig EmploymentStatus getEm Employment () {return this.employment; } public HomeownerStatus getHomeOwnerStatus () {return this.homeOwnerStatus; } / ** * Byggeklasse som beskrevet i den andre utgaven av Joshua Blochs * Effektiv Java som brukes til å bygge en {@link Person} -forekomst. * / public static class PersonBuilder {private FullName nestedName; privat adresse nestetAdresse; private Kjønn nestet Kjønn; privat EmploymentStatus nestetEm EmploymentStatus; private HuseierStatus nestetHomeEierStatus; offentlig PersonBuilder (endelig Fullnavn newFullName, endelig adresse newAddress) {this.nestedName = newFullName; this.nestedAddress = newAddress; } offentlig PersonBuilder-navn (endelig Fullnavn newName) {this.nestedName = newName; returner dette; } offentlig PersonBuilder-adresse (endelig adresse newAddress) {this.nestedAddress = newAddress; returner dette; } offentlig PersonBuilder-kjønn (endelig kjønn newGender) {this.nestedGender = newGender; returner dette; } offentlig ansettelse av PersonBuilder (endelig EmploymentStatus newEm EmploymentStatus) {this.nestedEm EmploymentStatus = newEmploymentStatus; returner dette; } public PersonBuilder homeOwner (final HomeownerStatus newHomeOwnerStatus) {this.nestedHomeOwnerStatus = newHomeOwnerStatus; returner dette; } offentlig person createPerson () {return new Person (nestedName, nestedAddress, nestedGender, nestedEmploymentStatus, nestedHomeOwnerStatus); }}} 

De siste par kodelistene viser hvordan en Builder vanligvis brukes - for å konstruere et objekt. Faktisk er varen på byggherren (Vare nr. 2) i Joshua Blochs andre utgave av effektiv Java i kapitlet om å skape (og ødelegge) objekt. Imidlertid kan byggeren hjelpe indirekte med ikke-konstruktørmetoder ved å tillate en enklere måte å bygge parametere objekter som sendes til metoder.

$config[zx-auto] not found$config[zx-overlay] not found