The Builder Pattern Criticism or Caveats
While the Builder pattern offers several advantages, developers should also be aware of its potential caveats and considerations. Here are some criticisms or caveats to keep in mind when deciding to use the Builder pattern
Implementation of the Builder pattern we have seen in the previous section:
interface ICustomer {
firstName: string;
lastName: string;
email: string;
phoneNumber: string;
}
interface ICustomerBuilder {
setFirstName(firstName: string): ICustomerBuilder;
setLastName(lastName: string): ICustomerBuilder;
setEmail(email: string): ICustomerBuilder;
setPhoneNumber(phoneNumber: string): ICustomerBuilder;
build(): ICustomer;
}
class Customer implements ICustomer {
constructor(
public firstName: string,
public lastName: string,
public email: string,
public phoneNumber: string
) {
// Customer constructor logic...
}
// Customer methods...
}
class CustomerBuilder implements ICustomerBuilder {
private firstName: string = "";
private lastName: string = "";
private email: string = "";
private phoneNumber: string = "";
setFirstName(firstName: string): ICustomerBuilder {
this.firstName = firstName;
return this;
}
setLastName(lastName: string): ICustomerBuilder {
this.lastName = lastName;
return this;
}
setEmail(email: string): ICustomerBuilder {
this.email = email;
return this;
}
setPhoneNumber(phoneNumber: string): ICustomerBuilder {
this.phoneNumber = phoneNumber;
return this;
}
build(): ICustomer {
return new Customer(
this.firstName,
this.lastName,
this.email,
this.phoneNumber
);
}
}
class CustomerDirector {
constructor(private builder: ICustomerBuilder) {}
construct(firstName: string, lastName: string, email: string): ICustomer {
return this.builder
.setFirstName(firstName)
.setLastName(lastName)
.setEmail(email)
.build();
}
}
// Usage example:
const builder: ICustomerBuilder = new CustomerBuilder();
const director: CustomerDirector = new CustomerDirector(builder);
const customer: ICustomer = director.construct(
"John",
"Doe",
"john.doe@example.com"
);
console.log(customer);
Increased Complexity
The Builder pattern introduces an additional layer of abstraction and more classes to the project. This could increase the complexity of the code and make it harder to understand and maintain for those not familiar with the Builder pattern.
This implementation has an interface and two classes (CustomerBuilder
and CustomerDirector
) to handle the creation of Customer
. This could be
considered as extra complexity if you compare it to simply instantiating
a Customer
object directly.
Additional Code
Implementation of the Builder pattern can result in significant additional code, especially for small classes with few fields. This may unnecessarily increase the size of the codebase.
The CustomerBuilder
class, with its multiple setter methods and a build
method, is the additional code which would not be necessary if the Customer
object was instantiated directly. This could be considered as a bloat for
smaller classes.
Runtime Errors
The lack of built-in compile-time checks can lead to runtime errors. For example, if you forget to set a required field in the builder, TypeScript won't notify you of this at compile-time.
In the provided example, nothing is preventing you from calling build()
on CustomerBuilder
without first setting all the required fields.
If Customer
constructor logic assumed that none of the fields will be
empty, this could lead to runtime errors.
Mutability Concerns
If the object that is being built has a complex structure or contains mutable objects, this can lead to issues if the Builder or the object it creates is not properly designed. Care must be taken to prevent mutability concerns and to ensure proper handling of complex objects.
Although not visible in this example, if Customer
had mutable objects as
fields, these would need to be handled correctly in the builder (i.e., deep
copied) to prevent unintentional sharing of mutable state.
Refactoring Difficulties
If you decide to change the structure of the class being built (like adding a new required field), you need to update the builder code as well. This can make refactoring a bit more difficult and time-consuming.
If you added a new field to the Customer
class, you would also need to add
a corresponding setter method in the CustomerBuilder
class and potentially
update the CustomerDirector
class as well.
Time To Transition From JavaScript To TypeScript
Level Up Your TypeScript And Object Oriented Programming Skills. The only complete TypeScript course on the marketplace you building TypeScript apps like a PRO.
SEE COURSE DETAILSPerformance
There may be some performance costs associated with using the builder pattern, as creating an object through a builder typically involves more steps and therefore more computational resources than direct instantiation. However, these costs are usually negligible and should not be a concern unless in a performance-critical context.
As evident from the usage example, creating a new Customer
instance now
involves creating a CustomerBuilder
instance, setting each field
individually, and finally calling build()
. This is certainly more
computationally intensive than simply instantiating Customer
directly.
Documentation
Given the extra complexity, developers must properly document how to use the builder class, particularly in API-like contexts where the built object is a part of the interface exposed to users or other parts of the project.
In this example, a new developer would need to understand the role
of CustomerBuilder
and CustomerDirector
classes and how to use them to
create a Customer
instance. This introduces an extra learning curve and
thus mandates good documentation.
Remember, as with any design pattern, the Builder pattern should be used judiciously. It is a great tool when dealing with objects that have many potential configuration options, but may be overkill for simple objects with only a few fields. Always evaluate the specific needs and constraints of your project before deciding to use a particular design pattern.
What Can You Do Next 🙏😊
If you liked the article, consider subscribing to Cloudaffle, my YouTube Channel, where I keep posting in-depth tutorials and all edutainment stuff for ssoftware developers.