Skip to main content
查利博客

Creational Design Pattern - Builder

The builder pattern is a creational design pattern that is used to create complex objects. When the number of instance fields of a class increases, the parameters of the constrcutor also increases. It is typically a bad practice to have too many parameters for a method (constructor is also a method). This amazing book Clean Code: A Handbook of Agile Software Craftsmanship suggests that we should not pass more than three parameters because you can hardly remember them. With builder pattern, we can eliminate the ugly and long parameter list in constructor. Many Java frameworks used this technique such as the HttpSecurity class in Spring Security and the HttpClient in Java 11 HTTP Client API. Below is a simple example that demonstrates the builder pattern.

Builder Pattern Example #

First we create a User class and a private contructor that accpets the UserBuilder parameter. Therefore now client can only create the User instance from the UserBuilder class because the constructor is private.

class User:

public class User {

  private String username;
  private int age;
  private String sex;
  private LocalDate dateOfBirth;

  private User(UserBuilder builder) {
    this.username = builder.username;
    this.age = builder.age;
    this.sex = builder.sex;
    this.dateOfBirth = builder.dateOfBirth;
  }
  // getters
  // toString
}

Next, we have to create the UserBuilder class (static) inside the User such that the builder can access those private instance fields and of course create the User object. The next step is to expose some public setters of UserBuilder and return itself to acheive the method chaining. Finally, expose a build() method that will create and return the User object to the client.

class UserBuilder:

public static class UserBuilder {
  private String username;
  private int age;
  private String sex;
  private LocalDate dateOfBirth;

  public UserBuilder setUsername(String username) {
    this.username = username;
    return this;
  }
  public UserBuilder setAge(int age) {
    this.age = age;
    return this;
  }
  public UserBuilder setSex(String sex) {
    this.sex = sex;
    return this;
  }
  public UserBuilder setDateOfBirth(LocalDate dateOfBirth) {
    this.dateOfBirth = dateOfBirth;
    return this;
  }

  public User build() {
    User user = new User(this);
    return user;
  }
}

Try our UserBuilder to create a User object:

public class BuilderExample {
  public static void main(String[] args) {
    User user = new UserBuilder().setUsername("rick")
        .setAge(12)
        .setSex("M")
        .setDateOfBirth(LocalDate.of(2009, 11, 12))
        .build();
    System.out.println(user);
  }
}

Output:

User [username=rick, age=12, sex=M, dateOfBirth=2009-11-12]