Design Principle #2: Consider using the builder pattern when there are many constructor arguments

Before jumping on to builder pattern, let’s talk about telescoping constructor (anti)-pattern and JavaBeans pattern.

In Java, it is not possible to set default values for constructor parameters. This is where the telescoping constructor pattern comes handy. A class has multiple constructors, where each constructor calls a more specific constructor in the hierarchy, which has more parameters than itself, providing a default value for the extra parameters. The next constructor does the same until there is no left. See below code for example.

public class Employee { 
    String firstName; 
    String lastName; 
    String streetAddress; 
    String country; 

    public Employee(String firstName, String lastName) { 
        this(firstName, lastName, null); 
    } 

    public Employee(String firstName, String lastName, String streetAddress) { 
        this(firstName, lastName, streetAddress, null); 
    } 

    public Employee(String firstName, String lastName, String streetAddress, String country) { 
        this.firstName = firstName; 
        this.lastName = lastName; 
        this.streetAddress = streetAddress; 
        this.country = country; 
    } 
}

 

Now, this pattern works fine when there are fewer parameters, but this does not scale well as the number of parameters increases. Also, it makes the code harder to read. The situation becomes even worse when the parameters are all of the same types.

An alternative to this approach is to use Java Beans Pattern. In this method, we can set the values by calling setters methods for each parameter.

public class Employee { 
    String firstName; 
    String lastName; 
    String streetAddress; 
    String country; 
    public Employee() {} 
    public void setFirstName(String firstName) { 
        this.firstName = firstName; 
    } 
    public void setLastName(String lastName) { 
        this.lastName = lastName; 
    } 
    public void setStreetAddress(String streetAddress) { 
        this.streetAddress = streetAddress; 
    } 
    public void setCountry(String country) { 
        this.country = country; 
    } 
}

 

Now, there are some serious disadvantages of using this pattern. First, it allows inconsistency. This means that the parameters values can be changed at part of the object lifecycle using setter methods. Second, the JavaBeans patters preclude the possibility of making a class immutable and requires an added effort from the developer to ensure thread safety.

There is another way which combines the safety of the telescoping constructor pattern with the readability of the JavaBeans pattern. This is given by Builder Pattern.

public class Employee { 
    private final String firstName; 
    private final String lastName; 
    private final String streetAddress; 
    private final String country; 
    class Builder{ 
        //Required parameters 
        private final String firstName; 
        private final String lastName; 

        //Optional parameters 
        private String streetAddress = null; 
        private String country = null; 
        public Builder(String firstName, String lastName) { 
            this.firstName = firstName; 
            this.lastName = lastName; 
        } 
        public Builder streetAddress(String streetAddress) { 
            this.streetAddress = streetAddress; 
            return this; 
        } 
        public Builder country(String country) { 
            this.country = country; 
            return this; 
        } 
        public Employee build() { 
            return new Employee(this); 
        } 
    } 
    private Employee(Builder builder) { 
        firstName = builder.firstName; 
        lastName = builder.lastName; 
        streetAddress = builder.streetAddress; 
        country = builder.country; 
    } 
}

We can initialize the Employee class using below invocation:

Employee employee = new Employee.Builder("John", "Doe").
                           streetAddress("700 Mission St").build();



The builder pattern is also well suited for class hierarchies. Overall, the builder pattern comes in useful when there are more than a handful number of parameters in a class and it is not mandatory to set a value for each one of them.

References: Effective Java by Joshua Bloch

One thought on “Design Principle #2: Consider using the builder pattern when there are many constructor arguments

Leave a comment