Tuesday, September 22, 2015

Effective Java - Item 2 : Consider a builder when faced with many constructor parameters

There will be many cases where the number of parameters to be passed for invoking a constructor/static factory method is huge (typically anything above 6). All the parameters may not be strictly required to create an object of that class but still the user will be forced to pass some values for all the parameters.
One solution is to create multiple constructors starting with a constructor with only the required parameters and then adding one optional parameter until we have covered all parameters. This option is called the telescoping constructor pattern.
An alternative solution is to use JavaBeans pattern. Here we can create the object by invoking a parameterless constructor and then calling settter methods to initialize the parameters. But JavaBeans pattern has it's own disadvantages.
The third and best alternative is to use the builder pattern where the client first calls a constructor/static factory with all the required parameters to get a builder object. The builder class provides setter methods to set the optional parameters. The client then calls a parameterless build method to generate the object. The builder is a static member class of the class it builds.

//Builder pattern   
  public class Person {   
   private final String firstName;   
   private final String middleName;   
   private final String lastName;   
   private final int age;   
   private final String streetAddress;   
   private final String city;   
   private final String state;   
   private final boolean isEmployed;   
     
   public static class PersonBuilder {   
     
    //Required parameters   
    private final String firstName;   
    private final String lastName;   
    private final int age;   
     
    //Optional parameters - initialized to default   
    private final String middleName = "";   
    private final String streetAddress = "";   
    private final String city = "";   
    private final String state = "";   
    private final boolean isEmployed = 0;   
     
    public PersonBuilder(String firstName, String lastName, int age) {   
     this.firstName = firstName;   
     this.lastName = lastName;   
     this.age = age;   
    }   
     
    public PersonBuilder setMiddleName(String middleName) {   
     this.middleName = middleName;   
     return this;   
    }   
     
    public PersonBuilder setStreetAddress(String streetAddress) {   
     this.streetAddress = streetAddress;   
     return this;   
    }   
     
    public PersonBuilder setCity(String city) {   
     this.city = city;   
     return this;   
    }   
     
    public PersonBuilder setState(String state) {   
     this.state = state;   
     return this;   
    }   
     
    public PersonBuilder setIsEmployed(boolean isEmployed) {   
     this.isEmployed = isEmployed;   
     return this;   
    }   
     
    public Person build() {   
     return new Person(this);   
    }   
   }   
     
   private Person(PersonBuilder personBuilder) {   
    firstName = personBuilder.firstName;   
    middleName = personBuilder.middleName;   
    lastName = personBuilder.lastName;   
    age = personBuilder.age;   
    streetAddress = personBuilder.streetAddress;   
    city = personBuilder.city;   
    state = personBuilder.state;   
    isEmployed = personBuilder.isEmployed;   
   }   
 }

The above example explains the builder method pattern with a Person class. Note that the builder's setter method returns the builder itself so we can chain the invocations as shown below

 Person person = new Person.PersonBuilder("John","Smith",25).setMiddleName("Snow").setCity("Arlington").setState("TX").setIsEmployed(1).build();  

As we can see the final code is simple and easy on the eyes.

No comments:

Post a Comment