Java - Builder Design Pattern - Example
Builder is a creational pattern that provides an efficient way to build objects. Compared with the traditional way of using multiple constructors, using the Builder pattern can ensure the readability and stability of the code. This mode is particularly useful when creating complex objects.
Use Builder pattern in the following situations:
- When the algorithm for creating a complex object should be independent of the object's components and how they are assembled
- When the construction process must allow the constructed object to have different representation
Advantages
1. It provides a clear disseverment between the construction and representation of an object.
2. It provides better control over the construction process.
3. It fortifies transmuting the internal representation of objects.
Implementation
Let's see an example and learn how to implement a builder pattern. Consider a POJO of Employee below.
public class Employee { // All final attributes private final String firstName; // required private final String lastName; // required private final int age; // optional private final String phone; // optional private final String address; // optional
private Employee(EmployeeBuilder builder) { this.firstName = builder.firstName; this.lastName = builder.lastName; this.age = builder.age; this.phone = builder.phone; this.address = builder.address; }
// All getter, and NO setter to provide immutability public String getFirstName() { return firstName; }
public String getLastName() { return lastName; }
public int getAge() { return age; }
public String getPhone() { return phone; }
public String getAddress() { return address; }
@Override public String toString() { return "Employee: " + this.firstName + ", " + this.lastName + ", " + this.age + ", " + this.phone + ", " + this.address; }
public static class EmployeeBuilder { private final String firstName; private final String lastName; private int age; private String phone; private String address;
public EmployeeBuilder(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; }
public EmployeeBuilder age(int age) { this.age = age; return this; }
public EmployeeBuilder phone(String phone) { this.phone = phone; return this; }
public EmployeeBuilder address(String address) { this.address = address; return this; }
// Return the finally constructed Employee object public Employee build() { Employee employee = new Employee(this); validateEmplopyeeObject(employee); return employee; }
private void validateEmplopyeeObject(Employee employee) { // Do some basic validations to check // if employee object does not break any assumption of system } }}
public class Employee { // All final attributes private final String firstName; // required private final String lastName; // required private final int age; // optional private final String phone; // optional private final String address; // optional
private Employee(EmployeeBuilder builder) { this.firstName = builder.firstName; this.lastName = builder.lastName; this.age = builder.age; this.phone = builder.phone; this.address = builder.address; }
// All getter, and NO setter to provide immutability public String getFirstName() { return firstName; }
public String getLastName() { return lastName; }
public int getAge() { return age; }
public String getPhone() { return phone; }
public String getAddress() { return address; }
@Override public String toString() { return "Employee: " + this.firstName + ", " + this.lastName + ", " + this.age + ", " + this.phone + ", " + this.address; }
public static class EmployeeBuilder { private final String firstName; private final String lastName; private int age; private String phone; private String address;
public EmployeeBuilder(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; }
public EmployeeBuilder age(int age) { this.age = age; return this; }
public EmployeeBuilder phone(String phone) { this.phone = phone; return this; }
public EmployeeBuilder address(String address) { this.address = address; return this; }
// Return the finally constructed Employee object public Employee build() { Employee employee = new Employee(this); validateEmplopyeeObject(employee); return employee; }
private void validateEmplopyeeObject(Employee employee) { // Do some basic validations to check // if employee object does not break any assumption of system } }}
Main class
public class BuilderPatternDemo { public static void main(String[] args) {
Employee employee1 = new Employee. EmployeeBuilder("Sibin", "Scott"). age(30). phone("9898989898") .address("YYYYYYYYYYY"). build(); System.out.println(employee1);
// No address Employee employee2 = new Employee. EmployeeBuilder("July", "Reacher"). age(40). phone("2132134242"). build(); System.out.println(employee2);
// No age // No phone // No address Employee employee3 = new Employee. EmployeeBuilder("He", "Man"). build(); System.out.println(employee3);
}}
Console Output:
Employee: Sibin, Scott, 30, 9898989898, YYYYYYYYYYY
Employee: July, Reacher, 40, 2132134242, null
Employee: He, Man, 0, null, null