Builder Design Pattern
What is a builder design pattern?
Builder design pattern allows us to construct complex objects step by step. It produces different types and representations of an object using the same construction process.
Builder is a creational design pattern
Advantages of builder design pattern:
- Reduces the code used to initialize the object
- The number of parameters in the constructor reduces and makes it very readable.
- It separates the construction and representation of an object.
- It provides better control over the object construction process.
- Immutable objects can be built without much complex logic in the object-building process.
- It supports changing the internal representation of objects.
Disadvantages of builder design pattern:
- It requires writing extra code to implement the builder, more code requires more maintenance.
- Requires creating a separate ConcreteBuilder for different types of objects.
Example of builder design pattern in TypeScript:
// Client.ts import {UserBuilder} from "./UserBuilder"; import {User} from "./User"; const userObj: User = new UserBuilder('Joe Smith') .setAge(24) .setPhone("01911016") .setAddress("Munich, Germany") .build(); console.log(userObj.getName() + " " + userObj.getAge() + " " + userObj.getPhone() + " " + userObj.getAddress()); // UserBuilder.ts import { User } from "./User"; export class UserBuilder { private name: string; private age: number; private phone: string; private address: string; constructor(name: string) { this.name = name; } getName() { return this.name; } setAge(value: number): UserBuilder { this.age = value; return this; } getAge() { return this.age; } setPhone(value: string): UserBuilder { this.phone = value; return this; } getPhone() { return this.phone; } setAddress(value: string): UserBuilder { this.address = value; return this; } getAddress() { return this.address; } build(): User { return new User(this); } } // User.ts import { UserBuilder } from "./UserBuilder"; export class User { private name: string; private age: number; private phone: string; private address: string; constructor(builder: UserBuilder) { this.name = builder.getName(); this.age = builder.getAge(); this.phone = builder.getPhone(); this.address = builder.getAddress() } getName() { return this.name; } getAge() { return this.age; } getPhone() { return this.phone; } getAddress() { return this.address; } }
Example of builder design pattern in Java:
// Product class: The object that will be built class House { // Required parameters private String foundation; private String structure; // Optional parameters private boolean hasGarage; private boolean hasSwimmingPool; private boolean hasGarden; // Private constructor to prevent direct instantiation private House(HouseBuilder builder) { this.foundation = builder.foundation; this.structure = builder.structure; this.hasGarage = builder.hasGarage; this.hasSwimmingPool = builder.hasSwimmingPool; this.hasGarden = builder.hasGarden; } // Getters for accessing properties public String getFoundation() { return foundation; } public String getStructure() { return structure; } public boolean hasGarage() { return hasGarage; } public boolean hasSwimmingPool() { return hasSwimmingPool; } public boolean hasGarden() { return hasGarden; } @Override public String toString() { return "House [Foundation=" + foundation + ", Structure=" + structure + ", Garage=" + hasGarage + ", Swimming Pool=" + hasSwimmingPool + ", Garden=" + hasGarden + "]"; } // Static nested builder class public static class HouseBuilder { // Required parameters private String foundation; private String structure; // Optional parameters private boolean hasGarage; private boolean hasSwimmingPool; private boolean hasGarden; // Constructor with required parameters public HouseBuilder(String foundation, String structure) { this.foundation = foundation; this.structure = structure; } // Setter methods for optional parameters public HouseBuilder setGarage(boolean hasGarage) { this.hasGarage = hasGarage; return this; // Return the builder to chain method calls } public HouseBuilder setSwimmingPool(boolean hasSwimmingPool) { this.hasSwimmingPool = hasSwimmingPool; return this; } public HouseBuilder setGarden(boolean hasGarden) { this.hasGarden = hasGarden; return this; } // Build method to construct the final House object public House build() { return new House(this); } } } // Client code to demonstrate the Builder pattern public class BuilderPatternExample { public static void main(String[] args) { // Creating a house using the builder House house = new House.HouseBuilder("Concrete", "Wood") .setGarage(true) .setSwimmingPool(false) .setGarden(true) .build(); System.out.println(house); } }