# Java Builder-Pattern - Introduction
I recently blogged about Static Factory Methods. Constructors and static factory methods have on thing in common: There are both not optimal, when having too many (optional) parameters.
# Telescoping-Constructor-Pattern
Let's take a simple Person-class with a Telescoping-Constructor-Pattern, which has multiple constructors to offer different ways to initiate the class.
public class Person
{
private String firstName; // required
private String lastName; // required
private String streetAddress;
private String streetNumber;
private String zipCode;
private String country;
public Person(String firstName, String lastName, String country)
{
this(firstName, lastName, null, null, null, country);
}
public Person(String firstName, String lastName)
{
this(firstName, lastName, null, null, null);
}
public Person(String firstName, String lastName, String streetAdress, String streetNumber, String zipCode)
{
this(firstName, lastName, streetAdress, streetNumber, zipCode, null);
}
public Person(String firstName, String lastName, String streetAddress, String streetNumber, String zipCode, String country)
{
this.firstName = firstName;
this.lastName = lastName;
this.streetAddress = streetAddress;
this.streetNumber = streetNumber;
this.zipCode = zipCode;
this.country = country;
}
...
}
This pattern has a couple of disadvantages:
- Bad readability due to the amount constructors
- Decreased maintainability
# JavaBeans-Pattern
An alternative is the JavaBeans-Pattern, where each member has a Getter and the class has an empty constructor.
public class Person
{
private String firstName; // required
private String lastName; // required
private String streetAddress;
private String streetNumber;
private String zipCode;
private String country;
public Person()
{
}
/\* Getter & Setter \*/
}
We may construct and use the class like this:
Person person = new Person();
person.setFirstName("First Name");
person.setLastName("Last Name");
person.setCountry("Country");
This solves the problems of the Telescoping-Constructor-Pattern with improved readability. However, this pattern allows inconsistency by splitting up the construction and value assignment. A easy-to-implement and good way to solve this, is using the Builder-Pattern.
# Java Builder-Pattern
Rather than instantiating the class directly, the client calls a constructor or static factory method and in return gets a Builder object. The client can now use setter-like methods to fill the optional parameters. To get the actual initiated object, the client calls the build() method.
Let's implement a simple builder pattern with out person class.
public class Person
{
private final String firstName; // required
private final String lastName; // required
private final String streetAddress;
private final String streetNumber;
private final String zipCode;
private final String country;
public static class Builder
{
private final String firstName; // required
private final String lastName; // required
private String streetAddress;
private String streetNumber;
private String zipCode;
private String country;
// Constructor of the builder contains the required members
public Builder(String firstName, String lastName)
{
this.firstName = firstName;
this.lastName = lastName;
}
public Builder streetAddress(String streetAddress)
{
this.streetAddress = streetAddress;
return this;
}
public Builder streetNumber(String streetNumber)
{
this.streetNumber = streetNumber;
return this;
}
public Builder zipCode(String zipCode)
{
this.zipCode = zipCode;
return this;
}
public Builder country(String country)
{
this.country = country;
return this;
}
@Override
public Person build()
{
return new Person(this);
}
}
private Person(Builder builder)
{
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.streetAddress = builder.streetAddress;
this.streetNumber = builder.streetNumber;
this.zipCode = builder.zipCode;
this.country = builder.country;
}
}
The constructor is private by intention to allow the user to only use the builder.
To create a person, we can now use the builder like this:
Person person = new Person.Builder("Kevin", "G").country("Deutschland").build();
Person person2 = new Person.Builder("Kevin", "G").build();
Person person3 = new Person.Builder("Kevin", "G").streetAddress("Adresse").streetNumber("4").zipCode("21220").country("Deutschland").build();
As you can see, the Java Builder-Pattern has advantages over the Constructors and Static Factory Methods, if we have a lot of parameters.
This post was inspired by Effective Java - Second Edition von Joshua Bloch (opens new window).
If you like this post, feel free to follow me or hit me up on Twitter (opens new window).