Programmering

For mange parametre i Java-metoder, del 3: Builder-mønster

I mine to umiddelbart tidligere indlæg kiggede jeg på at reducere antallet af parametre, der kræves for en konstruktør eller metodeopkald via brugerdefinerede typer og parameterobjekter. I dette indlæg ser jeg på brugen af ​​bygningsmønsteret for at reducere antallet af parametre, der kræves for en konstruktør, med en vis diskussion om, hvordan dette mønster endda kan hjælpe med ikke-konstruktormetoder, der tager for mange parametre.

I anden udgave af effektiv Java introducerer Josh Bloch brug af bygningsmønsteret i punkt 2 til håndtering af konstruktører, der kræver for mange parametre. Bloch demonstrerer ikke kun, hvordan man bruger Builder, men forklarer det fordele i forhold til konstruktører, der accepterer et stort antal parametre. Jeg kommer til disse fordele i slutningen af ​​dette indlæg, men synes det er vigtigt at påpege, at Bloch har afsat et helt emne i sin bog til denne praksis.

For at illustrere fordelene ved denne tilgang bruger jeg følgende eksempel Person klasse. Det har ikke alle de metoder, jeg typisk vil føje til en sådan klasse, fordi jeg vil fokusere på dens konstruktion.

Person.java (uden bygmønster)

pakke dustin. eksempler; / ** * Personklasse brugt som del af demonstration af for mange parametre. * * @forfatter Dustin * / person i offentlig klasse {privat endelig streng efternavn; privat final String firstName; privat endelig Streng mellemnavn; privat endelig String hilsen; privat endelig streng-suffiks; privat endelig String streetAddress; privat finale Strengby; privat endelig strengstat; privat final boolsk isFemale; privat endelig boolsk er ansat; privat endelig boolsk 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 klasses konstruktør fungerer, men det er vanskeligt for klientkoden at bruge korrekt. Builder-mønsteret kan bruges til at gøre konstruktøren lettere at bruge. NetBeans vil refakte dette for mig, som jeg tidligere har skrevet om. Et eksempel på den refactored kode vises derefter (NetBeans gør dette ved at oprette 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; privat String newStreetAddress; private String newCity; privat String newState; private boolske newIsFemale; private boolske nyeIsEmbled; privat boolsk newIsHomeOwner; public PersonBuilder () {} public PersonBuilder setNewLastName (String newLastName) {this.newLastName = newLastName; returner dette; } offentlig PersonBuilder setNewFirstName (String newFirstName) {this.newFirstName = newFirstName; returner dette; } offentlig 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 setNewIsEmployed (boolsk newIsEm Employed) {this.newIsEmployed = newIsEm Employed; returner dette; } offentlig PersonBuilder setNewIsHomeOwner (boolsk newIsHomeOwner) {this.newIsHomeOwner = newIsHomeOwner; returner dette; } offentlig person createPerson () {returner ny person (newLastName, newFirstName, newMiddleName, newSalutation, newSuffix, newStreetAddress, newCity, newState, newIsFemale, newIsEmployed, newIsHomeOwner); }} 

Jeg foretrækker at have min Builder som en indlejret klasse inden for den klasse, hvis objekt den bygger, men NetBeans automatiske generation af en standalone Builder er meget nem at bruge. En anden forskel mellem den NetBeans-genererede Builder og de Builders, som jeg gerne vil skrive, er at mine foretrukne Builder-implementeringer har krævet felter, der er angivet i Builder's konstruktør snarere end at give en konstruktør uden argumenter. Den næste kodeliste viser min Person klasse ovenfra med en Builder tilføjet til den som en indlejret klasse.

Person.java med indlejret Person.Builder

pakke dustin. eksempler; / ** * Personklasse, der bruges som en del af demonstrationen af ​​for mange parametre. * * @forfatter Dustin * / person i offentlig klasse {privat endelig streng efternavn; privat final String firstName; privat endelig Streng mellemnavn; privat endelig String hilsen; privat endelig streng-suffiks; privat endelig String streetAddress; privat finale Strengby; privat endelig strengstat; privat endelig boolsk isFemale; privat endelig boolsk er ansat; privat endelig boolsk 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. endelig boolsk. 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 streng indlejretSalutation; privat streng indlejretSuffix; privat streng indlejretStreetAddress; privat streng nestedCity; privat streng indlejret stat; private boolske indlejredeIsFemale; private boolske indlejredeIsEmbled; privat boolsk indlejretIsHomeOwner; public PersonBuilder (final String newFirstName, final String newCity, final String newState) {this.nestedFirstName = newFirstName; this.nestedCity = newCity; this.nestedState = newState; } offentlig PersonBuilder efternavn (String 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; } offentlig PersonBuilder-hilsen (String newSalutation) {this.nestedSalutation = newSalutation; returner dette; } offentligt suffiks til PersonBuilder (String newSuffix) {this.nestedSuffix = newSuffix; returner dette; } offentlig PersonBuilder streetAddress (String newStreetAddress) {this.nestedStreetAddress = newStreetAddress; returner dette; } offentlig PersonBuilder by (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 isEmployed (boolean newIsEm Employed) {this.nestedIsEmployed = newIsEm Employed; returner dette; } offentlig PersonBuilder isHomeOwner (boolsk newIsHomeOwner) {this.nestedIsHomeOwner = newIsHomeOwner; returner dette; } offentlig person createPerson () {returner ny person (nestedLastName, nestedFirstName, nestedMiddleName, nestedSalutation, nestedSuffix, nestedStreetAddress, nestedCity, nestedState, nestedIsFemale, nestedIsEmployed, nestedIsHomeOwner); }}} 

Builder kan være endnu pænere, når den forbedres ved hjælp af brugerdefinerede typer og parametreobjekter som beskrevet i mine første to indlæg om "for mange parametre" -problemet. Dette vises i den næste kodeliste.

Person.java med Nested Builder, brugerdefinerede typer og parametreobjekt

pakke dustin. eksempler; / ** * Personklasse brugt som del af demonstration af for mange parametre. * * @forfatter Dustin * / person i offentlig klasse {privat endelig fuldnavn navn; privat endelig adresse adresse; privat endelig køn; privat endelig EmploymentStatus ansættelse; privat endelig HomeownerStatus homeOwnerStatus; / ** * Parametreret konstruktør kan være privat, fordi kun min interne bygherre * skal ringe til mig for at give en instans til klienter. * * @param newName Navn på denne person. * @param newAddress Adresse til denne person. * @param newGender Køn for denne person. * @param newBeskæftigelse Beskæftigelsesstatus for denne person. * @param newHomeOwner Status for ejerskab af denne person. * / privat person (endelig fuldnavn nyt navn, endelig adresse ny adresse, endelig køn ny køn, endelig beskæftigelsesstatus ny beskæftigelse, endelig boligejerstatus ny hjemmehjælper) {this.name = newname; this.address = newAddress; this.gender = newGender; denne. beskæftigelse = ny beskæftigelse; this.homeOwnerStatus = newHomeOwner; } offentlig Fullnavn getName () {returner dette.navn; } offentlig adresse getAddress () {returner denne.adresse; } offentlig køn getGender () {returner dette. køn; } offentlig BeskæftigelseStatus getEm Employment () {returner denne. beskæftigelse; } public HomeownerStatus getHomeOwnerStatus () {returner this.homeOwnerStatus; } / ** * Byggeklasse som beskrevet i anden udgave af Joshua Blochs * Effektiv Java der bruges til at oprette en {@link Person} -forekomst. * / public static class PersonBuilder {private FullName nestedName; privat adresse indlejretAdresse; privat Køn indlejretKøn; privat beskæftigelsesstatus indlejretEmplacementstatus; privat boligejerStatus indlejretHomeEjerStatus; offentlig PersonBuilder (endelig Fullnavn newFullName, endelig adresse newAddress) {this.nestedName = newFullName; this.nestedAddress = newAddress; } offentligt PersonBuilder navn (endelig FullName newName) {this.nestedName = newName; returner dette; } offentlig PersonBuilder-adresse (endelig adresse newAddress) {this.nestedAddress = newAddress; returner dette; } offentligt PersonBuilder-køn (endelig Køn newGender) {this.nestedGender = newGender; returner dette; } offentlig ansættelse af PersonBuilder (endelig EmploymentStatus newEm EmploymentStatus) {this.nestedEm EmploymentStatus = newEmploymentStatus; returner dette; } offentlig PersonBuilder homeOwner (endelig HomeownerStatus newHomeOwnerStatus) {this.nestedHomeOwnerStatus = newHomeOwnerStatus; returner dette; } offentlig person createPerson () {returner ny person (nestedName, nestedAddress, nestedGender, nestedEmploymentStatus, nestedHomeOwnerStatus); }}} 

De sidste par kodelister viser, hvordan en Builder typisk bruges - til at konstruere et objekt. Faktisk er genstanden om bygherren (vare nr. 2) i Joshua Blochs anden udgave af effektiv Java i kapitlet om at skabe (og ødelægge) objekt. Imidlertid kan bygherren hjælpe indirekte med ikke-konstruktormetoder ved at give en lettere måde at opbygge parametre objekter, der sendes til metoder.

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