Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

When to use builder pattern

When a class requires more arguments to instantiate then it is better to go for a builder pattern. Let me explain with an example.

For example, you are developing an application to maintain all the employees’ information of organization ‘ABC’. Initially, I designed Employee model class like below.

Approach 1: Design Employee model class by providing setter and getter methods.

Employee.java
public class Employee {
private int id;
private String firstName;
private String lastName;
private float salary;
private String designation;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getFirstName() {
return firstName;
}

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

public String getLastName() {
return lastName;
}

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

public float getSalary() {
return salary;
}

public void setSalary(float salary) {
this.salary = salary;
}

public String getDesignation() {
return designation;
}

public void setDesignation(String designation) {
this.designation = designation;
}

}

There is a problem with this approach. Since Employee class provides setter methods, you can’t make the Employee class immutable.

Approach 2: We can make the class ‘Employee’ immutable, by not providing setter methods and providing different combinations of constructors to initialize instance properties.

Employee.java
public class Employee {
private int id;
private String firstName;
private String lastName;
private float salary;
private String designation;

private static final String DEFAULT_NAME = "no_name";
private static final int DEFAULT_ID = -1;
private static final String DEFAULT_DESIGNATION = "Engineer";
private static final float DEFAULT_SALARY = 25000;

public Employee() {
this(DEFAULT_ID, DEFAULT_NAME, DEFAULT_NAME, DEFAULT_SALARY, DEFAULT_DESIGNATION);
}

public Employee(int id) {
this(id, DEFAULT_NAME, DEFAULT_NAME, DEFAULT_SALARY, DEFAULT_DESIGNATION);
}

public Employee(int id, String firstName) {
this(id, firstName, DEFAULT_NAME, DEFAULT_SALARY, DEFAULT_DESIGNATION);
}

public Employee(int id, String firstName, String lastName) {
this(id, firstName, lastName, DEFAULT_SALARY, DEFAULT_DESIGNATION);
}

public Employee(int id, String firstName, String lastName, float salary, String designation) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.salary = salary;
this.designation = designation;
}

public int getId() {
return id;
}

public String getFirstName() {
return firstName;
}

public String getLastName() {
return lastName;
}

public float getSalary() {
return salary;
}

public String getDesignation() {
return designation;
}

}

There is a problem with above model class, As you see the definition of Employee class, I provided 4 different constructors to initialize different combination of properties. What if my class has more instance properties, I will end up in more and more constructor definitions, which is not feasible. We can solve both the problems by providing builder object.

Approach 3: Define Employee model class using builder pattern.

Employee.java
public class Employee {
private int id;
private String firstName;
private String lastName;
private float salary;
private String designation;

private Employee() {

}

public int getId() {
return id;
}

public String getFirstName() {
return firstName;
}

public String getLastName() {
return lastName;
}

public float getSalary() {
return salary;
}

public String getDesignation() {
return designation;
}

public static class EmployeeBuilder {

private static final String DEFAULT_NAME = "no_name";
private static final int DEFAULT_ID = -1;
private static final String DEFAULT_DESIGNATION = "Engineer";
private static final float DEFAULT_SALARY = 25000;

private int id;
private String firstName;
private String lastName;
private float salary;
private String designation;

public EmployeeBuilder() {
this.id = DEFAULT_ID;
this.firstName = this.lastName = DEFAULT_NAME;
this.salary = DEFAULT_SALARY;
this.designation = DEFAULT_DESIGNATION;
}

public EmployeeBuilder id(int id) {
this.id = id;
return this;
}

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

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

public EmployeeBuilder salary(float salary) {
this.salary = salary;
return this;
}

public EmployeeBuilder designation(String designation) {
this.designation = designation;
return this;
}

public Employee build() {
Employee emp = new Employee();
emp.designation = this.designation;
emp.firstName = this.firstName;
emp.id = this.id;
emp.lastName = lastName;
emp.salary = salary;
return emp;
}
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Employee [id=").append(id).append(", firstName=").append(firstName).append(", lastName=")
.append(lastName).append(", salary=").append(salary).append(", designation=").append(designation)
.append("]");
return builder.toString();
}

}

Test.java
public class Test {

public static void main(String args[]) {

Employee.EmployeeBuilder builder = new Employee.EmployeeBuilder();

Employee emp = builder.id(553)
.firstName("Hari krishna")
.lastName("Gurram")
.designation("Software Engineer")
.build();

System.out.println(emp);
}

}

Output
Employee [id=553, firstName=Hari krishna, lastName=Gurram, salary=25000.0, designation=Software Engineer]

In real world applications, it is always good coding practice to code for an interface. For example, you can define a Builder interface like below, and make the EmployeeBuilder class implements the Builder interface.

public interface BuilderT> {
public T build();
}

Implement EmployeeBuilder like below.
public static class EmployeeBuilder implements BuilderEmployee> {

private static final String DEFAULT_NAME = "no_name";
private static final int DEFAULT_ID = -1;
private static final String DEFAULT_DESIGNATION = "Engineer";
private static final float DEFAULT_SALARY = 25000;

private int id;
private String firstName;
private String lastName;
private float salary;
private String designation;

public EmployeeBuilder() {
this.id = DEFAULT_ID;
this.firstName = this.lastName = DEFAULT_NAME;
this.salary = DEFAULT_SALARY;
this.designation = DEFAULT_DESIGNATION;
}

public EmployeeBuilder id(int id) {
this.id = id;
return this;
}

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

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

public EmployeeBuilder salary(float salary) {
this.salary = salary;
return this;
}

public EmployeeBuilder designation(String designation) {
this.designation = designation;
return this;
}

@Override
public Employee build() {
Employee emp = new Employee();
emp.designation = this.designation;
emp.firstName = this.firstName;
emp.id = this.id;
emp.lastName = lastName;
emp.salary = salary;
return emp;
}
}
You may like
How to resolve Circular Dependency Problem
What is ReentrantLock?
Non-Blocking Algorithms
Implement Thread Pool in Java
Why to use static factory methods over constructors
Java Interview Questions





This post first appeared on Java Tutorial : Blog To Learn Java Programming, please read the originial post: here

Share the post

When to use builder pattern

×

Subscribe to Java Tutorial : Blog To Learn Java Programming

Get updates delivered right to your inbox!

Thank you for your subscription

×