Ohjelmointi

Liian monta parametria Java-menetelmissä, osa 3: Rakentajan malli

Kaksi välittömästi edellistä viestiäni tarkastelin konstruktorin tai menetelmän kutsumiseen tarvittavien parametrien määrän vähentämistä mukautettujen tyyppien ja parametriobjektien avulla. Tässä viestissä tarkastelen rakentajan mallin käyttöä vähentämään konstruktorille tarvittavien parametrien määrää keskustelemalla siitä, kuinka tämä malli voi jopa auttaa muiden kuin rakentajien menetelmissä, jotka vievät liian monta parametria.

Toisen Java-version toisessa versiossa Josh Bloch esittelee kohteen # 2 rakennustekniikan käytön käsiteltäessä rakentajia, jotka vaativat liikaa parametreja. Bloch ei vain osoita Builderin käyttöä, vaan selittää sen edut verrattuna rakentajiin, jotka hyväksyvät suuren määrän parametreja. Pääsen noihin etuihin tämän viestin lopussa, mutta mielestäni on tärkeää huomauttaa, että Bloch on omistanut kirjassaan kokonaisen kohteen tähän käytäntöön.

Käytän seuraavaa esimerkkiä havainnollistaakseni tämän lähestymistavan etuja Henkilö luokassa. Sillä ei ole kaikkia menetelmiä, jotka tyypillisesti lisätään tällaiseen luokkaan, koska haluan keskittyä sen rakentamiseen.

Person.java (ilman rakentajakuviota)

pakkaus pölyä.esimerkkejä; / ** * Henkilöluokka, jota käytetään osana liian monta parametrien esittelyä. * * @author Dustin * / julkisen luokan henkilö {yksityinen lopullinen merkkijono sukunimi; yksityinen lopullinen String firstName; yksityinen lopullinen merkkijono middleName; yksityinen loppukielen tervehdys; yksityinen lopullinen merkkijono; yksityinen lopullinen String streetAddress; yksityinen lopullinen Jousikaupunki; yksityinen lopullinen merkkijono; yksityinen lopullinen totuusarvo on Nainen; yksityinen lopullinen totuusarvo onTyöllinen; yksityinen lopullinen looginen arvo onKotiomistaja; public Person (viimeinen merkkijono newLastName, viimeinen merkkijono newFirstName, viimeinen merkkijono newMiddleName, viimeinen merkkijono newSalutation, viimeinen merkkijono newSuffix, viimeinen merkkijono newStreetAddress, viimeinen merkkijono newCity, viimeinen merkkijono newState, lopullinen boolen newIsFemale, lopullinen boolean newIsEweaner, viimeinen boolean tämä. sukunimi = uusiLastName; this.esinimi = newFirstName; this.middleName = newMiddleName; this.salutation = newSalutation; this.suffix = newSuffix; this.streetAddress = newStreetAddress; this.city = newCity; this.state = newState; this.isFemale = uusiIsFemale; this.isEmployed = newIsEmployed; this.isHomewOwner = newIsHomeOwner; }} 

Tämän luokan konstruktori toimii, mutta asiakaskoodia on vaikea käyttää oikein. Builder-mallia voidaan käyttää rakentajan käytön helpottamiseen. NetBeans refraktoi tämän minulle, kuten olen aiemmin kirjoittanut. Seuraava esimerkki uudistetusta koodista (NetBeans tekee tämän luomalla kaikki uudet Builder-luokat).

PersonBuilder.java

pakkaus pölyä.esimerkkejä; public class PersonBuilder {private String newLastName; yksityinen merkkijono newFirstName; yksityinen merkkijono newMiddleName; yksityinen merkkijono newSalutation; yksityinen merkkijono newSuffix; yksityinen merkkijono newStreetAddress; yksityinen merkkijono newCity; yksityinen merkkijono newState; yksityinen totuusarvo newIsFemale; yksityinen boolen uusiIsEmployed; yksityinen looginen uusiIsHomeOwner; public PersonBuilder () {} public PersonBuilder setNewLastName (String newLastName) {this.newLastName = newLastName; palauta tämä; } public PersonBuilder setNewFirstName (Merkkijono newFirstName) {this.newFirstName = newFirstName; palauta tämä; } public PersonBuilder setNewMiddleName (Merkkijono newMiddleName) {this.newMiddleName = newMiddleName; palauta tämä; } public PersonBuilder setNewSalutation (String newSalutation) {this.newSalutation = newSalutation; palauta tämä; } public PersonBuilder setNewSuffix (String newSuffix) {this.newSuffix = newSuffix; palauta tämä; } public PersonBuilder setNewStreetAddress (String newStreetAddress) {this.newStreetAddress = newStreetAddress; palauta tämä; } public PersonBuilder setNewCity (String newCity) {this.newCity = newCity; palauta tämä; } public PersonBuilder setNewState (String newState) {this.newState = newState; palauta tämä; } public PersonBuilder setNewIsFemale (looginen newIsFemale) {this.newIsFemale = newIsFemale; palauta tämä; } public PersonBuilder setNewIsEmployed (looginen newIsEmployed) {this.newIsEmployed = newIsEmployed; palauta tämä; } public PersonBuilder setNewIsHomeOwner (looginen newIsHomeOwner) {this.newIsHomeOwner = newIsHomeOwner; palauta tämä; } public Person createPerson () {return new Person (uusiLastName, newFirstName, newMiddleName, newSalutation, newSuffix, newStreetAddress, newCity, newState, newIsFemale, newIsEmployed, newIsHomeOwner); }} 

Pidän Builderiani mieluummin sisäkkäisenä luokkana sen luokan sisällä, jonka objektin se rakentaa, mutta erillisen Builderin automaattinen NetBeans-sukupolvi on erittäin helppokäyttöinen. Toinen ero NetBeansin luoman rakennustyökalun ja haluamieni kirjoittajien välillä on se, että suosittelemani rakentajan toteutustavat ovat vaatineet kenttiä Builderin konstruktorissa sen sijaan, että niissä olisi argumentteja sisältämätön rakentaja. Seuraava koodiluettelo näyttää minun Henkilö luokka ylhäältä ja Builder lisätty siihen sisäkkäisenä luokkana.

Person.java sisäkkäisen Person.Builderin kanssa

pakkaus pölyä.esimerkkejä; / ** * Henkilöluokka, jota käytetään osana liian monta parametrien esittelyä. * * @author Dustin * / julkisen luokan henkilö {yksityinen lopullinen merkkijono sukunimi; yksityinen lopullinen String firstName; yksityinen lopullinen merkkijono middleName; yksityinen loppukielen tervehdys; yksityinen lopullinen merkkijono-pääte; yksityinen lopullinen String streetAddress; yksityinen lopullinen Jousikaupunki; yksityinen lopullinen merkkijono; yksityinen lopullinen totuusarvo on Nainen; yksityinen lopullinen totuusarvo onTyöllinen; yksityinen lopullinen looginen arvo onKotiomistaja; public Person (viimeinen merkkijono newLastName, viimeinen merkkijono newFirstName, viimeinen merkkijono newMiddleName, viimeinen merkkijono newSalutation, viimeinen merkkijono newSuffix, viimeinen merkkijono newStreetAddress, viimeinen merkkijono newCity, viimeinen merkkijono newState, lopullinen boolen newIsFemale, lopullinen boolean newIsEweaner, viimeinen boolean tämä. sukunimi = uusiLastName; this.esinimi = newFirstName; this.middleName = newMiddleName; this.salutation = newSalutation; this.suffix = newSuffix; this.streetAddress = newStreetAddress; this.city = newCity; this.state = newState; this.isFemale = uusiIsFemale; this.isEmployed = newIsEmployed; this.isHomewOwner = newIsHomeOwner; } public staattinen luokka PersonBuilder {private String nestedLastName; yksityinen merkkijono nestedFirstName; yksityinen merkkijono nestedMiddleName; yksityinen merkkijono sisäkkäinSalutation; yksityinen merkkijono sisäkkäinSuffix; yksityinen merkkijono nestedStreetAddress; yksityinen merkkijono nestedCity; yksityinen merkkijono nestedState; yksityinen looginen sisäkkäinIsFemale; yksityinen looginen sisäkkäinIsEmployed; yksityinen boolen sisäkkäinIsHomeOwner; public PersonBuilder (viimeinen merkkijono newFirstName, viimeinen merkkijono newCity, viimeinen merkkijono newState) {this.nestedFirstName = newFirstName; this.nestedCity = newCity; this.nestedState = newState; } public PersonBuilder lastName (String newLastName) {this.nestedLastName = newLastName; palauta tämä; } public PersonBuilder firstName (String newFirstName) {this.nestedFirstName = newFirstName; palauta tämä; } public PersonBuilder middleName (Merkkijono newMiddleName) {this.nestedMiddleName = newMiddleName; palauta tämä; } julkinen PersonBuilder-tervehdys (String newSalutation) {this.nestedSalutation = newSalutation; palauta tämä; } public PersonBuilder -pääte (String newSuffix) {this.nestedSuffix = newSuffix; palauta tämä; } public PersonBuilder streetAddress (String newStreetAddress) {this.nestedStreetAddress = newStreetAddress; palauta tämä; } public PersonBuilder city (String newCity) {this.nestedCity = newCity; palauta tämä; } public PersonBuilder -tila (String newState) {this.nestedState = newState; palauta tämä; } public PersonBuilder isFemale (looginen newIsFemale) {this.nestedIsFemale = newIsFemale; palauta tämä; } public PersonBuilder isEmployed (looginen newIsEmployed) {this.nestedIsEmployed = newIsEmployed; palauta tämä; } public PersonBuilder isHomeOwner (looginen newIsHomeOwner) {this.nestedIsHomeOwner = newIsHomeOwner; palauta tämä; } public Person createPerson () {return new Person (sisäkkäinViimeNimi, sisäkkäinenEnsinimi, sisäkkäinenMiddleName, sisäkkäinSalutation, sisäkkäinenSuffix, sisäkkäinenStreetAddress, sisäkkäinenKaupunki, sisäkkäinenSate, sisäkkäinIsanainen, sisäkkäinIsEmployed, sisäkkäinenIsHomeOwner); }}} 

Rakentaja voi olla vielä mukavampi, kun sitä parannetaan käyttämällä mukautettuja tyyppejä ja parametreja, kuten kahdessa ensimmäisessä viestissäni "liian monta parametriä" -ongelmasta hahmotellaan. Tämä näkyy seuraavassa koodiluettelossa.

Person.java sisäkkäisen rakennustyökalun, mukautettujen tyyppien ja parametrien objektin kanssa

pakkaus pölyä.esimerkkejä; / ** * Henkilöluokka, jota käytetään osana liian monta parametrien esittelyä. * * @author Dustin * / julkinen luokka Henkilö {yksityinen lopullinen KokoNimi; yksityinen lopullinen Osoite-osoite; yksityinen lopullinen Sukupuoli; yksityinen lopullinen EmploymentStatus-työpaikka; yksityinen lopullinen HomeownerStatus homeOwnerStatus; / ** * Parametroitu rakennuttaja voi olla yksityinen, koska vain sisäisen rakennustyökaluni * täytyy soittaa minulle, jotta asiakkaalle voidaan tarjota ilmentymä. * * @param newName Tämän henkilön nimi. * @param newAddress Tämän henkilön osoite. * @param newGender Tämän henkilön sukupuoli. * @param newEmployment Tämän henkilön työllisyysaste. * @param newHomeOwner Tämän henkilön omistustila. * / yksityishenkilö (lopullinen KokoNimi uusiNimi, lopullinen osoite newAddress, lopullinen Sukupuoli newGender, lopullinen EmploymentStatus newEmployment, lopullinen AsunnonomistajaStatus newHomeOwner) {this.name = newName; this.osoite = uusiosoite; this.gender = newGender; this.employment = newEmployment; this.homeOwnerStatus = newHomeOwner; } public KokoNimi getName () {palauta tämä.nimi; } public address getAddress () {palauta tämä.osoite; } public Gender getGender () {return this.gender; } public EmploymentStatus getEmployment () {return this.employment; } public homeownerStatus getHomeOwnerStatus () {return this.homeOwnerStatus; } / ** * Rakentaja-luokka Joshua Blochin toisen painoksen * mukaisesti Tehokas Java jota käytetään {@link Person} -instanssin rakentamiseen. * / public staattinen luokka PersonBuilder {private FullName nestedName; yksityinen osoite nestedAddress; yksityinen Sukupuoli sisäkkäinenGender; yksityinen EmploymentStatus nestedEmploymentStatus; yksityinen asunnon omistajaStatus sisäkkäinHomeOwnerStatus; public PersonBuilder (lopullinen KokoNimi newFullName, lopullinen osoite newAddress) {this.nestedName = newFullName; this.nestedAddress = newAddress; } public PersonBuilder -nimi (lopullinen KokoNimi newName) {this.nestedName = newName; palauta tämä; } public PersonBuilder address (viimeinen osoite newAddress) {this.nestedAddress = newAddress; palauta tämä; } public PersonBuilder-sukupuoli (lopullinen sukupuoli newGender) {this.nestedGender = newGender; palauta tämä; } public PersonBuilder -työntekijä (lopullinen EmploymentStatus newEmploymentStatus) {this.nestedEmploymentStatus = newEmploymentStatus; palauta tämä; } public PersonBuilder homeOwner (viimeinen kodinomistajan tila newHomeOwnerStatus) {this.nestedHomeOwnerStatus = newHomeOwnerStatus; palauta tämä; } public Person createPerson () {return new Person (sisäkkäinenNimi, sisäkkäinenosoite, sisäkkäissukupuoli, sisäkkäinenEmploymentStatus, sisäkkäinenHomeOwnerStatus); }}} 

Viimeiset koodiluettelot osoittavat, kuinka rakennustyökalua tyypillisesti käytetään - objektin rakentamiseen. Joshua Blochin tehokkaan Java: n toisen painoksen rakennustyökalulla oleva kohta (kohta # 2) on todellakin objektin luomista (ja tuhoamista) koskevassa luvussa. Rakentaja voi kuitenkin auttaa epäsuorasti muilla kuin rakentajamenetelmillä antamalla helpomman tavan rakentaa menetelmille välitettäviä parametriobjekteja.

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