Programování

Příliš mnoho parametrů v metodách Java, část 3: Tvůrce

V mých dvou bezprostředně předchozích příspěvcích jsem se podíval na snížení počtu parametrů požadovaných pro vyvolání konstruktoru nebo metody pomocí vlastních typů a objektů parametrů. V tomto příspěvku se podívám na použití vzoru stavitele ke snížení počtu parametrů požadovaných pro konstruktor s nějakou diskusí o tom, jak tento vzor může dokonce pomoci s metodami bez konstruktoru, které berou příliš mnoho parametrů.

Ve druhém vydání Effective Java zavádí Josh Bloch použití vzoru stavitele v položce č. 2 pro práci s konstruktory, kteří vyžadují příliš mnoho parametrů. Bloch nejen předvádí, jak používat Builder, ale vysvětluje jeho výhody oproti konstruktérům, kteří přijímají velké množství parametrů. K těmto výhodám se dostanu na konci tohoto příspěvku, ale myslím, že je důležité zdůraznit, že Bloch této praxi věnoval celou položku ve své knize.

Pro ilustraci výhod tohoto přístupu použiji následující příklad Osoba třída. Nemá všechny metody, které bych do takové třídy obvykle přidal, protože se chci zaměřit na její konstrukci.

Person.java (bez vzoru stavitele)

příklady zásilky; / ** * Třída osob použitá jako součást ukázky příliš mnoha parametrů. * * @author Dustin * / public class Osoba {private final String lastName; private final Řetězec firstName; private final Řetězec prostřední jméno; soukromý závěrečný pozdrav řetězce; soukromá koncová přípona řetězce; soukromá konečná String streetAddress; soukromé konečné město String; soukromý konečný stav řetězce; soukromá závěrečná boolean isFemale; private final boolean isEmployed; private final boolean 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 newIs 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.isEmployed = newIsEmployed; this.isHomewOwner = newIsHomeOwner; }} 

Konstruktor této třídy funguje, ale je obtížné, aby se kód klienta správně používal. Vzor Builder lze použít k usnadnění použití konstruktoru. NetBeans to za mě refaktoruje, jak jsem již psal. Příklad refaktorovaného kódu je zobrazen dále (NetBeans to dělá vytvořením nové třídy Builder).

PersonBuilder.java

příklady zásilky; public class PersonBuilder {private String newLastName; soukromý řetězec newFirstName; soukromý řetězec newMiddleName; soukromý řetězec newSalutation; soukromý řetězec newSuffix; soukromý řetězec newStreetAddress; soukromý řetězec newCity; soukromý řetězec newState; soukromý boolean newIsFemale; soukromý boolean newIsEmployed; soukromý logický newIsHomeOwner; public PersonBuilder () {} public PersonBuilder setNewLastName (řetězec newLastName) {this.newLastName = newLastName; vrátit to; } public PersonBuilder setNewFirstName (řetězec newFirstName) {this.newFirstName = newFirstName; vrátit to; } public PersonBuilder setNewMiddleName (řetězec newMiddleName) {this.newMiddleName = newMiddleName; vrátit to; } public PersonBuilder setNewSalutation (String newSalutation) {this.newSalutation = newSalutation; vrátit to; } public PersonBuilder setNewSuffix (řetězec newSuffix) {this.newSuffix = newSuffix; vrátit to; } public PersonBuilder setNewStreetAddress (řetězec NewStreetAddress) {this.newStreetAddress = newStreetAddress; vrátit to; } public PersonBuilder setNewCity (String newCity) {this.newCity = newCity; vrátit to; } public PersonBuilder setNewState (String newState) {this.newState = newState; vrátit to; } public PersonBuilder setNewIsFemale (boolean newIsFemale) {this.newIsFemale = newIsFemale; vrátit to; } public PersonBuilder setNewIsEmployed (boolean newIsEmployed) {this.newIsEmployed = newIsEmployed; vrátit to; } public PersonBuilder setNewIsHomeOwner (boolean newIsHomeOwner) {this.newIsHomeOwner = newIsHomeOwner; vrátit to; } public Person createPerson () {return new Person (newLastName, newFirstName, newMiddleName, newSalutation, newSuffix, newStreetAddress, newCity, newState, newIsFemale, newIsEmployed, newIsHomeOwner); }} 

Dávám přednost tomu, aby byl můj Builder jako vnořená třída uvnitř třídy, jejíž objekt staví, ale automatické generování samostatného Builderu NetBeans je velmi snadné. Další rozdíl mezi NetBeans generovaným Builderem a Buildery, které rád píšu, je, že moje preferované implementace Builderu mají požadovaná pole poskytovaná v konstruktoru Builderu, místo aby poskytovala konstruktor bez argumentů. Další výpis kódu ukazuje můj Osoba třída shora s přidaným Builderem jako vnořená třída.

Person.java s vnořeným Person.Builderem

příklady zásilky; / ** * Třída osob použitá jako součást ukázky příliš mnoha parametrů. * * @author Dustin * / public class Osoba {private final String lastName; private final Řetězec firstName; private final Řetězec prostřední jméno; soukromý závěrečný pozdrav řetězce; soukromá koncová přípona řetězce; soukromá konečná String streetAddress; soukromé konečné město String; soukromý konečný stav řetězce; soukromá závěrečná boolean isFemale; private final boolean isEmployed; soukromý poslední boolean jeHomewOwner; 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 newIs 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.isEmployed = newIsEmployed; this.isHomewOwner = newIsHomeOwner; } veřejná statická třída PersonBuilder {soukromý řetězec nestedLastName; private String nestedFirstName; soukromý řetězec nestedMiddleName; private String nestedSalutation; private String nestedSuffix; private String nestedStreetAddress; private String nestedCity; private String nestedState; private boolean nestedIsFemale; private boolean nestedIsEmployed; soukromý boolean nestedIsHomeOwner; public PersonBuilder (final String newFirstName, final String newCity, final String newState) {this.nestedFirstName = newFirstName; this.nestedCity = newCity; this.nestedState = newState; } public PersonBuilder lastName (String newLastName) {this.nestedLastName = newLastName; vrátit to; } public PersonBuilder křestní jméno (řetězec newFirstName) {this.nestedFirstName = newFirstName; vrátit to; } public PersonBuilder prostřední_jméno (řetězec newMiddleName) {this.nestedMiddleName = newMiddleName; vrátit to; } veřejné oslovení PersonBuilder (řetězec newSalutation) {this.nestedSalutation = newSalutation; vrátit to; } veřejná přípona PersonBuilder (řetězec newSuffix) {this.nestedSuffix = newSuffix; vrátit to; } public PersonBuilder streetAddress (řetězec newStreetAddress) {this.nestedStreetAddress = newStreetAddress; vrátit to; } veřejné město PersonBuilder (řetězec newCity) {this.nestedCity = newCity; vrátit to; } public State PersonBuilder state (String newState) {this.nestedState = newState; vrátit to; } public PersonBuilder isFemale (boolean newIsFemale) {this.nestedIsFemale = newIsFemale; vrátit to; } public PersonBuilder isEmployed (boolean newIsEmployed) {this.nestedIsEmployed = newIsEmployed; vrátit to; } public PersonBuilder isHomeOwner (boolean newIsHomeOwner) {this.nestedIsHomeOwner = newIsHomeOwner; vrátit to; } public Person createPerson () {return new Person (nestedLastName, nestedFirstName, nestedMiddleName, nestedSalutation, nestedSuffix, nestedStreetAddress, nestedCity, nestedState, nestedIsFemale, nestedIsEmployed, nestedIsHomeOwner); }}} 

Tvůrce může být ještě hezčí, když je vylepšen pomocí použití vlastních typů a parametrů objektů, jak je uvedeno v mých prvních dvou příspěvcích o problému "příliš mnoho parametrů". To se zobrazuje v následujícím seznamu kódů.

Person.java s vnořeným tvůrcem, vlastními typy a objektem parametrů

příklady zásilky; / ** * Třída osob použitá jako součást ukázky příliš mnoha parametrů. * * @author Dustin * / veřejná třída Osoba {private final Celé jméno; konečná soukromá adresa; soukromé konečné pohlaví; soukromé konečné zaměstnání Zaměstnanost ve stavu; soukromý finální HomeownerStatus homeOwnerStatus; / ** * Parametrovaný konstruktor může být soukromý, protože pouze můj interní tvůrce * mi musí zavolat, abych poskytl instanci klientům. * * @param newName Jméno této osoby. * @param newAddress Adresa této osoby. * @param newGender Pohlaví této osoby. * @param newEmployment Pracovní status této osoby. * @param newHomeOwner Stav vlastnictví domácnosti této osoby. * / soukromá osoba (konečný FullName newName, konečná adresa newAddress, konečná pohlaví newGender, konečná EmploymentStatus newEmployment, konečná HomeownerStatus newHomeOwner) {this.name = newName; this.address = newAddress; this.gender = newGender; this.employment = newEmployment; this.homeOwnerStatus = newHomeOwner; } veřejné Celé jméno getName () {vrátit toto.název; } veřejná adresa getAddress () {vrátit tuto.adresu; } public Gender getGender () {vrátit this.gender; } public EmploymentStatus getEmployment () {return this.employment; } public HomeownerStatus getHomeOwnerStatus () {vrátit this.homeOwnerStatus; } / ** * Třída Builder, jak je uvedeno ve druhém vydání knihy Joshua Blocha * Efektivní Java který se používá k vytvoření instance {@link Person}. * / public static class PersonBuilder {private FullName nestedName; soukromá adresa nestedAddress; private Gender nestedGender; soukromý EmploymentStatus nestedEmploymentStatus; private HomeownerStatus nestedHomeOwnerStatus; public PersonBuilder (konečné FullName newFullName, konečná adresa newAddress) {this.nestedName = newFullName; this.nestedAddress = newAddress; } veřejné jméno PersonBuilder (konečné jméno FullName newName) {this.nestedName = newName; vrátit to; } veřejná adresa PersonBuilderu (konečná adresa newAddress) {this.nestedAddress = newAddress; vrátit to; } public PersonBuilder gender (final Gender newGender) {this.nestedGender = newGender; vrátit to; } veřejné zaměstnání PersonBuilder (konečné EmploymentStatus newEmploymentStatus) {this.nestedEmploymentStatus = newEmploymentStatus; vrátit to; } public PersonBuilder homeOwner (konečný HomeownerStatus newHomeOwnerStatus) {this.nestedHomeOwnerStatus = newHomeOwnerStatus; vrátit to; } public Person createPerson () {return new Person (nestedName, nestedAddress, nestedGender, nestedEmploymentStatus, nestedHomeOwnerStatus); }}} 

Poslední pár výpisů kódu ukazuje, jak se obvykle používá Builder - ke konstrukci objektu. Položka na staviteli (Položka č. 2) ve druhém vydání Efektivní Javy od Joshua Blocha je v kapitole o vytváření (a ničení) objektů. Tvůrce však může nepřímo pomoci s metodami bez konstruktoru tím, že umožní snadnější způsob sestavení parametrů objektů, které se předávají metodám.