Builder Design Pattern in Java for Beginners

Omkar Kulkarni
Javarevisited
Published in
4 min readJan 2, 2021
Photo by Guilherme Cunha on Unsplash

Builder Design Pattern is a creational design pattern used for the creation of complex objects. While creating objects from a constructor with more than four parameters we are more prone to making errors. Even if one parameter gets switched or missed, a considerable amount of time is consumed to find out what has gone wrong.

public class Customer {
public String name;
public String firstName;
public String lastName;
public int age;
public String address;
public String city;
public String mobileNumber;
public String pincode;

public Customer(String name,
String firstName,
String lastName,
int age,
String address,
String city,
String mobileNumber,
String pincode) {
this.name = name;
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.address = address;
this.city = city;
this.mobileNumber = mobileNumber;
this.pincode = pincode;
}
}

Consider the above example, the object creation requires eight parameters, if you miss even one then be ready to spend time on finding what is going wrong. Now, what if the customer does not provide firstName and lastName explicitly? We would have to create one more constructor, which would not accept those two parameters.

public Customer(String name, int age, String address, String city, String mobileNumber, String pincode) {
this.name = name;
this.age = age;
this.address = address;
this.city = city;
this.mobileNumber = mobileNumber;
this.pincode = pincode;
}

If in the near future one more parameter gets added we will have to add one more constructor or edit the previous one and also add the parameter wherever the constructor has been used. Enter the Builder Design pattern our savior. It not only helps to create objects easily, but it also helps us to maintain the code in the long run. Let's see how this is implemented.

public class Customer {
public String name;
public String firstName;
public String lastName;
public int age;
public String address;
public String city;
public String mobileNumber;
public String pincode;

public String getName() {
return name;
}

public String getFirstName() {
return firstName;
}

public String getLastName() {
return lastName;
}

public int getAge() {
return age;
}

public String getAddress() {
return address;
}

public String getCity() {
return city;
}

public String getMobileNumber() {
return mobileNumber;
}

public String getPincode() {
return pincode;
}

@Override
public String toString() {
return "Customer{" +
"name='" + name + '\'' +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", age=" + age +
", address='" + address + '\'' +
", city='" + city + '\'' +
", mobileNumber='" + mobileNumber + '\'' +
", pincode='" + pincode + '\'' +
'}';
}

private Customer(CustomerBuilder customerBuilder) {
this.name = customerBuilder.name;
this.firstName = customerBuilder.firstName;
this.lastName = customerBuilder.lastName;
this.pincode = customerBuilder.pincode;
this.address = customerBuilder.address;
this.mobileNumber = customerBuilder.mobileNumber;
this.age = customerBuilder.age;
this.city = customerBuilder.city;
}

public static class CustomerBuilder {
private String name;
private String firstName;
private String lastName;
private int age;
private String address;
private String city;
private String mobileNumber;
private String pincode;

public CustomerBuilder() {
}

public CustomerBuilder setName(String name) {
this.name = name;
return this;
}

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

public CustomerBuilder setLastName(String lastName) {
this.lastName = lastName;
return this;
}

public CustomerBuilder setAge(int age) {
this.age = age;
return this;
}

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

public CustomerBuilder setCity(String city) {
this.city = city;
return this;
}

public CustomerBuilder setMobileNumber(String mobileNumber) {
this.mobileNumber = mobileNumber;
return this;
}

public CustomerBuilder setPincode(String pincode) {
this.pincode = pincode;
return this;
}

public Customer build() {
return new Customer(this);
}
}
}

Things to note:

  1. There is a static inner class that can return the object.
  2. The static class has the setters and has also had a build() method which would return the new Customer object.
  3. The outer class only has getters which helps us to fetch the fields that are set.

Let's see how would we instantiate the Customer Object

public class BuilderClassImplementation {
public static void main(String[] args) {
Customer customer = new Customer.CustomerBuilder()
.setName("Omkar Kulkarni")
.setFirstName("Omkar")
.setLastName("Kulkarni")
.setMobileNumber("8551223****")
.build();
}
}

Advantages :

  1. Passing so many parameters to the constructor is eliminated.
  2. We do not have to pass null inside the constructor.
  3. Code is maintainable.
  4. We can force immutability once the object is created.

Disadvantages :

  1. Code has been duplicated inside the inner and the outer class.
  2. The instance might get created without the parameters as well.

There might be a case where we need to have some parameters mandatory but with the above implementation, the object might get created parameterless.

So in that case we need a bit of tweaking inside the builder class implementation. Instead of having an empty constructor, we pass the mandatory fields that might be required for the object creation.

Here goes the constructor implementation.

public CustomerBuilder(String name, int age, String city) {
this.name = name;
this.age = age;
this.city = city;
}

And the object instantiation would also change because of this.

Customer customer = new Customer
.CustomerBuilder("Omkar", 29, "Pune")
.setMobileNumber("987*******")
.build();

Conclusion:

Builder Design Pattern a creational Design Pattern should be used for creating complex objects. The code becomes maintainable and less error-prone.

--

--