Terlalu Banyak Parameter dalam Kaedah Java, Bahagian 3: Corak Pembina

Dalam dua posting saya yang sebelumnya, saya melihat untuk mengurangkan bilangan parameter yang diperlukan untuk pemanggil konstruk atau kaedah melalui jenis khusus dan objek parameter. Dalam catatan ini, saya melihat penggunaan corak pembangun untuk mengurangkan bilangan parameter yang diperlukan untuk konstruktor dengan beberapa perbincangan mengenai bagaimana corak ini dapat membantu kaedah bukan konstruktor yang mengambil terlalu banyak parameter.

Dalam Edisi Kedua Java Berkesan, Josh Bloch memperkenalkan penggunaan corak pembangun dalam Item # 2 untuk menangani pembangun yang memerlukan terlalu banyak parameter. Bloch tidak hanya menunjukkan cara menggunakan Builder, tetapi menjelaskan kelebihannya berbanding konstruktor yang menerima sebilangan besar parameter. Saya akan mendapat kelebihan tersebut pada akhir catatan ini, tetapi berpendapat penting untuk menunjukkan bahawa Bloch telah menumpukan keseluruhan item dalam bukunya untuk latihan ini.

Untuk menggambarkan kelebihan pendekatan ini, saya akan menggunakan Personkelas contoh berikut . Ia tidak mempunyai semua kaedah yang biasanya saya tambahkan ke kelas seperti itu kerana saya ingin menumpukan pada pembinaannya.

Person.java (tanpa Corak Pembina)

package dustin.examples; /** * Person class used as part of too many parameters demonstration. * * @author Dustin */ public class Person { private final String lastName; private final String firstName; private final String middleName; private final String salutation; private final String suffix; private final String streetAddress; private final String city; private final String state; private final 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 newIsHomeOwner) { this.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; } } 

Pembina kelas ini berfungsi, tetapi sukar bagi kod pelanggan untuk digunakan dengan betul. Corak Pembina boleh digunakan untuk menjadikan konstruktor lebih mudah digunakan. NetBeans akan memberikan penekanan semula kepada saya seperti yang telah saya tulis sebelum ini. Contoh kod refactored ditunjukkan seterusnya (NetBeans melakukan ini dengan membuat semua kelas Builder baru).

PersonBuilder.java

package dustin.examples; public class PersonBuilder { private String newLastName; private String newFirstName; private String newMiddleName; private String newSalutation; private String newSuffix; private String newStreetAddress; private String newCity; private String newState; private boolean newIsFemale; private boolean newIsEmployed; private boolean newIsHomeOwner; public PersonBuilder() { } public PersonBuilder setNewLastName(String newLastName) { this.newLastName = newLastName; return this; } public PersonBuilder setNewFirstName(String newFirstName) { this.newFirstName = newFirstName; return this; } public PersonBuilder setNewMiddleName(String newMiddleName) { this.newMiddleName = newMiddleName; return this; } public PersonBuilder setNewSalutation(String newSalutation) { this.newSalutation = newSalutation; return this; } public PersonBuilder setNewSuffix(String newSuffix) { this.newSuffix = newSuffix; return this; } public PersonBuilder setNewStreetAddress(String newStreetAddress) { this.newStreetAddress = newStreetAddress; return this; } public PersonBuilder setNewCity(String newCity) { this.newCity = newCity; return this; } public PersonBuilder setNewState(String newState) { this.newState = newState; return this; } public PersonBuilder setNewIsFemale(boolean newIsFemale) { this.newIsFemale = newIsFemale; return this; } public PersonBuilder setNewIsEmployed(boolean newIsEmployed) { this.newIsEmployed = newIsEmployed; return this; } public PersonBuilder setNewIsHomeOwner(boolean newIsHomeOwner) { this.newIsHomeOwner = newIsHomeOwner; return this; } public Person createPerson() { return new Person(newLastName, newFirstName, newMiddleName, newSalutation, newSuffix, newStreetAddress, newCity, newState, newIsFemale, newIsEmployed, newIsHomeOwner); } } 

Saya lebih suka menjadikan Builder saya sebagai kelas bersarang di dalam kelas yang objeknya bina, tetapi generasi automatik NetBeans Builder yang berdiri sendiri sangat mudah digunakan. Perbezaan lain antara Pembangun yang dihasilkan oleh NetBeans dan Pembangun yang ingin saya tulis adalah bahawa pelaksanaan Builder pilihan saya memerlukan bidang yang disediakan dalam pembangun Builder daripada menyediakan pembina tanpa argumen. Penyenaraian kod seterusnya menunjukkan Personkelas saya dari atas dengan Builder ditambahkan ke dalamnya sebagai kelas bersarang.

Person.java dengan Nested Person.Builder

package dustin.examples; /** * Person class used as part of too many parameters demonstration. * * @author Dustin */ public class Person { private final String lastName; private final String firstName; private final String middleName; private final String salutation; private final String suffix; private final String streetAddress; private final String city; private final String state; private final 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 newIsHomeOwner) { this.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; } public static class PersonBuilder { private String nestedLastName; private String nestedFirstName; private String nestedMiddleName; private String nestedSalutation; private String nestedSuffix; private String nestedStreetAddress; private String nestedCity; private String nestedState; private boolean nestedIsFemale; private boolean nestedIsEmployed; private 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; return this; } public PersonBuilder firstName(String newFirstName) { this.nestedFirstName = newFirstName; return this; } public PersonBuilder middleName(String newMiddleName) { this.nestedMiddleName = newMiddleName; return this; } public PersonBuilder salutation(String newSalutation) { this.nestedSalutation = newSalutation; return this; } public PersonBuilder suffix(String newSuffix) { this.nestedSuffix = newSuffix; return this; } public PersonBuilder streetAddress(String newStreetAddress) { this.nestedStreetAddress = newStreetAddress; return this; } public PersonBuilder city(String newCity) { this.nestedCity = newCity; return this; } public PersonBuilder state(String newState) { this.nestedState = newState; return this; } public PersonBuilder isFemale(boolean newIsFemale) { this.nestedIsFemale = newIsFemale; return this; } public PersonBuilder isEmployed(boolean newIsEmployed) { this.nestedIsEmployed = newIsEmployed; return this; } public PersonBuilder isHomeOwner(boolean newIsHomeOwner) { this.nestedIsHomeOwner = newIsHomeOwner; return this; } public Person createPerson() { return new Person( nestedLastName, nestedFirstName, nestedMiddleName, nestedSalutation, nestedSuffix, nestedStreetAddress, nestedCity, nestedState, nestedIsFemale, nestedIsEmployed, nestedIsHomeOwner); } } } 

Pembina boleh menjadi lebih baik apabila disempurnakan melalui penggunaan objek jenis dan parameter khusus seperti yang digariskan dalam dua catatan pertama saya mengenai masalah "terlalu banyak parameter". Ini ditunjukkan dalam senarai kod seterusnya.

Person.java dengan Pembangun Bersarang, Jenis Tersuai, dan Objek Parameter

package dustin.examples; /** * Person class used as part of too many parameters demonstration. * * @author Dustin */ public class Person { private final FullName name; private final Address address; private final Gender gender; private final EmploymentStatus employment; private final HomeownerStatus homeOwnerStatus; /** * Parameterized constructor can be private because only my internal builder * needs to call me to provide an instance to clients. * * @param newName Name of this person. * @param newAddress Address of this person. * @param newGender Gender of this person. * @param newEmployment Employment status of this person. * @param newHomeOwner Home ownership status of this person. */ private Person( final FullName newName, final Address newAddress, final Gender newGender, final EmploymentStatus newEmployment, final HomeownerStatus newHomeOwner) { this.name = newName; this.address = newAddress; this.gender = newGender; this.employment = newEmployment; this.homeOwnerStatus = newHomeOwner; } public FullName getName() { return this.name; } public Address getAddress() { return this.address; } public Gender getGender() { return this.gender; } public EmploymentStatus getEmployment() { return this.employment; } public HomeownerStatus getHomeOwnerStatus() { return this.homeOwnerStatus; } /** * Builder class as outlined in the Second Edition of Joshua Bloch's * Effective Java that is used to build a {@link Person} instance. */ public static class PersonBuilder { private FullName nestedName; private Address nestedAddress; private Gender nestedGender; private EmploymentStatus nestedEmploymentStatus; private HomeownerStatus nestedHomeOwnerStatus; public PersonBuilder( final FullName newFullName, final Address newAddress) { this.nestedName = newFullName; this.nestedAddress = newAddress; } public PersonBuilder name(final FullName newName) { this.nestedName = newName; return this; } public PersonBuilder address(final Address newAddress) { this.nestedAddress = newAddress; return this; } public PersonBuilder gender(final Gender newGender) { this.nestedGender = newGender; return this; } public PersonBuilder employment(final EmploymentStatus newEmploymentStatus) { this.nestedEmploymentStatus = newEmploymentStatus; return this; } public PersonBuilder homeOwner(final HomeownerStatus newHomeOwnerStatus) { this.nestedHomeOwnerStatus = newHomeOwnerStatus; return this; } public Person createPerson() { return new Person( nestedName, nestedAddress, nestedGender, nestedEmploymentStatus, nestedHomeOwnerStatus); } } } 

Beberapa senarai kod terakhir menunjukkan bagaimana Builder biasanya digunakan - untuk membina objek. Sesungguhnya, item pada pembangun (Item # 2) di Joshua Bloch Edisi Kedua Berkesan Java ada dalam bab membuat (dan memusnahkan) objek. Walau bagaimanapun, pembina dapat membantu secara tidak langsung dengan kaedah bukan konstruktor dengan membenarkan cara yang lebih mudah untuk membina parameter objek yang diteruskan ke kaedah.