Sitemap
Press enter or click to view image in full size
Photo by Nubelson Fernandes on Unsplash

Builder Pattern in Salesforce Apex

The builder pattern is a creational design pattern that facilitates the step-by-step instantiation of an object or a class reference. In this pattern, the object’s construction is separated from its representation, enabling the creation of diverse variations of an object using the same construction code.

Get Pijush Kar’s stories in your inbox

Join Medium for free to get updates from this writer.

This pattern is particularly useful when a class constructor requires multiple arguments for instantiation, or when an instance needs various configurations while keeping the construction process unchanged. It significantly enhances code readability, reusability, and simplifies the object’s construction process.

Traditional Object Construction Example

In a conventional object construction scenario —

// Employee class
public with sharing class Employee {
private String firstName;
private String lastName;
private String email;
private String department;
private String employeeId;

public Employee(
String firstName,
String lastName,
String email,
String department,
String employeeId
) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.department = department;
this.employeeId = employeeId;
}
}

The Employee object’s instantiation involves passing multiple arguments to the constructor in a specific order. Any alteration in argument positions during instantiation can lead to undesired outcomes. Moreover, the constructor’s signature is tightly bound, allowing exactly five arguments (string or null) to be passed.

Implementing Builder Pattern

To mitigate these limitations, adopting the Builder Pattern offers a more flexible approach —

// Employee class
public with sharing class Employee {
private String firstName;
private String lastName;
private String email;
private String department;
private String employeeId;

// Optional getters to access the Employee properties
public String getFirstName() {
return this.firstName;
}

public String getLastName() {
return this.lastName;
}

public String getEmail() {
return this.email;
}

public String getDepartment() {
return this.department;
}

public String getEmployeeId() {
return this.employeeId;
}
} //End of Employee class

// Builder class for Employee - separate construction
public with sharing class EmployeeBuilder {
private Employee employee;

public EmployeeBuilder() {
this.employee = new Employee();
}

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

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

public EmployeeBuilder setEmail(String email) {
this.employee.email = email;
return this;
}

public EmployeeBuilder setDepartment(String department) {
this.employee.department = department;
return this;
}

public EmployeeBuilder setEmployeeId(String employeeId) {
this.employee.employeeId = employeeId;
return this;
}

public Employee build() {
return this.employee;
}
}

Here, we have separated the construction of the Employee object in the EmployeeBuilder class. This allows for a step-by-step construction using setters, providing more flexibility and eliminating positional arguments.

Utilizing the EmployeeBuilder

Below EmployeeUtil class demonstrates the usage of EmployeeBuilder to create an Employee object —

public with sharing class EmployeeUtil {
public static Employee createEmployee() {
// Creating an EmployeeBuilder
EmployeeBuilder builder = new EmployeeBuilder()
.setFirstName("John")
.setLastName("Doe")
.setEmail("john.doe@example.com")
.setDepartment("IT")
.setEmployeeId("EMP001");

// Building an Employee
Employee employee = builder.build();

// Return constructed employee. Optionally output the Employee details with getters
return employee;
}
}

Now, consider a scenario where we require creating employees with specific roles such as manager, developer, or a salesperson. Instead of altering the EmployeeBuilder or the construction process itself, we can create a Director class to accommodate these variations and also to encapsulate the construction process —

// Director class for Employee construction
public class EmployeeDirector {
private EmployeeBuilder builder;

public EmployeeDirector(EmployeeBuilder builder) {
this.builder = builder;
}

public EmployeeBuilder constructManager() {
return builder.setEmail("sales.india@example.com")
.setDepartment("Management");
}

public EmployeeBuilder constructDeveloper() {
return builder.setEmail("devs.india@example.com")
.setDepartment("Development");
}

public EmployeeBuilder constructSalesperson() {
return builder.setEmail("sales.india@example.com")
.setDepartment("Sales");
}
}

Enhanced Usage with Director

Leveraging the EmployeeDirector class to create Employees with different roles —

// Usage of EmployeeDirector
public with sharing class EmployeeUtil {
//..
//..
//..Rest of the code remains same
public static void createEmployees(){
// Creating an EmployeeBuilder
EmployeeBuilder builder = new EmployeeBuilder();

// Creating a Director with the specified builder
EmployeeDirector director = new EmployeeDirector(builder);

Employee developer = director.constructDeveloper()
.setFirstName("John")
.setLastName("Brown")
.setEmployeeId("EMP004")
.build();

Employee manager = director.constructManager()
.setFirstName("John")
.setLastName("Doe")
.setEmployeeId("EMP007")
.build();
}
}

This modification allows the EmployeeDirector to handle the creation of Employees with different roles using the specified configurations, maintaining the separation of concerns between the Director and the Builder classes.

Written by Pijush Kar

Solving CRM needs in Salesforce platform | Igniting success one code at a time. 🚀