Builder Design Pattern – Implementation in Java

I have discussed Singleton PatternObserver PatternFactory Pattern, Decorator Pattern, and Command Pattern in my previous posts. In this one I will be talking about the Builder Design Pattern.

What is the Builder Design Pattern?

Builder pattern helps us in creating an immutable class with a large set of state attributes. One of the popular methods of implementing a class when you want to have an immutable object is to define a constructor with all the parameters, and no setter methods.

For example: Defining a user class with Firstname, Lastname, age, email.

public class User {
private String firstName;
private String lastName;
private int age;
private String email;
public User(String firstname, String lastname, int age, String email) {
this.firstname = firstname;
this.lastname = lastname;
this.age = age;
this.email = email;
}
}

What happens if some of these fields are optional. You have 2 options:

  1. Expect the clients to pass null for these fields.
    If you add a new field to this class, all these clients will have to be edited.
  2. Have as many constructors as there are combinations of these fields.
    You will have a bloated class if the number of fields are on the higher side.

Builder pattern helps address this issue without giving up on the immutability of the class.

Java Implementation

  1. Create a User class, make the constructor private, so that objects of this class cannot be built directly.
  2. Create a UserBuilder class. This will be the builder class for our user class.
package builder;
public class User {
private String firstName;
private String lastName;
private int age;
private String email;
private User(UserBuilder builder) {
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.age = builder.age;
this.email = builder.email;
}
@Override
public String toString() {
return "User: "+this.firstName+", "+this.lastName+", "+this.age+", "+this.email;
}
public static class UserBuilder {
private final String firstName;
private final String lastName;
private int age;
private String email;
public UserBuilder(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
public UserBuilder email(String email) {
this.email = email;
return this;
}
public User build() {
User user = new User(this);
return user;
}
}
}

Using this pattern (Main)

package builder;
public class Main {
public static void main(String[] args) {
User user1 = new User.UserBuilder("Anjana", "Shankar")
.build();
System.out.println(user1);
User user2 = new User.UserBuilder("Random", "User1")
.age(40)
.build();
System.out.println(user2);
User user3 = new User.UserBuilder("Random", "User2")
.age(40)
.email("randomuser2@email.com")
.build();
System.out.println(user3);
}
}

As you see above, you have the flexibility of adding none or more optional attributes.

You can find the complete code on Github.

Advantages of Builder Design Pattern

  1. It helps in providing code readability and design flexibility.
  2. There is no need to pass in null for optional parameters to the constructor.
  3. Object is always instantiated with a complete state.
  4. Building an immutable object does not require complex logic at the time of building.

Disadvantages of Builder Design Pattern

  1. The number of lines of code more than doubles due to the builder class.

Builder Pattern in Java Library

The widely used StringBuilder and StringBuffer are both good examples of Builder pattern.

Reference

https://howtodoinjava.com/design-patterns/creational/builder-pattern-in-java/