The Builder Pattern in Java

The Builder pattern is a creational design pattern which can be used to address the telescoping constructor anti-pattern. It accomplishes this by separating the construction of an object from its representation.

Telescoping constructor anti-pattern

This pattern arises when there are multiple ways of constructing an object, usually because some properties are optional. You can see that as the number of fields for an object increases, the number of constructors we need to provide can grow exponentially:

public class Person {
  private String firstName; //required
  private String surname;   //optional
  private String address;   //optional

  public Person(String firstName) {
    this.firstName = firstName;
  }

  public Person(String firstName, String surname) {
    this.firstName = firstName;
    this.surname = surname;
  }

  public Person(String firstName, String surname, String address) {
    this.firstName = firstName;
    this.surname = surname;
    this.address = address;
  }

  public Person(String firstName, String address) {
    this.firstName = firstName;
    this.address = address;
  }
}

Using a JavaBean

Instead of providing constructors we could write a JavaBean which exposes getters and setters for each field:

public class Person {
  private String firstName;
  private String surname;
  private String address;

  public getFirstName() {
    return this.firstName;
  }

  public setFirstName(String firstName) {
    this.firstName = firstName;
  }

  ...
}

and then only call the setters for the fields we want to set:

Person person = new Person();
person.setName("Jack");
person.setSurname("Johnson");

The problem with this is that the object may be in an inconsistent state partway through its construction. Also, the JavaBeans pattern doesn’t allow us to make the class immutable.

Using a builder

The third option is to use the builder pattern where Person is only used to represent a person and Person.Builder is responsible for creating objects of type Person:

2016 01 09 builder

This is how we could add a Builder to the example above:

public class Person {
  private String firstName;
  private String surname;
  private String address;

  private Person(Builder builder) {
    this.firstName = builder.firstName;
    this.surname = builder.surname;
    this.address = builder.address;
  }

  public static class Builder {
    private String firstName;
    private String surname;
    private String address;

    Builder(String firstName) {
      this.firstName = firstName;
    }

    public Builder surname(String surname) {
      this.surname = surname;
      return this;
    }

    public Builder address(String address) {
      this.address = address;
      return this;
    }

    public Person createPerson() {
      return new Person(this);
    }
  }
}

Note that the constructor for Person is private, accessible only to the Builder. Then we use the builder like this:

Person jack = new Person.Builder("Jack").surname("Johnson")
                                        .createPerson();

As you can see the client works with a fluent API, that is very easy to write. It is immediately clear that name is a required parameter and surname and address are optional.

IntelliJ IDEA refactoring

IntelliJ has a nice Replace Constructor with Builder refactoring which allows you to quickly generate a builder and replace the existing constructor call:

2016 01 09 refactor constructor with builder

When you generate the builder you can also use the Move Refactoring to make it an inner class of the class for which it generates an object:

2016 01 09 move

You can find this pattern and many other good practices for Java described in the book Effective Java by Joshua Bloch.