Builder Design Pattern in JavaScript

1. Definition

The Builder Design Pattern is a creational pattern that allows for the step-by-step construction of complex objects using the specific steps of a defined process. It separates the construction of a complex object from its representation.

2. Problem Statement

Imagine you're developing a feature to create different types of user profiles. A profile could have several attributes, some mandatory and some optional. Constructing such profiles using traditional constructors might lead to a plethora of different constructors or confusing function calls with numerous arguments.

3. Solution

The Builder pattern solves this problem by allowing the production of various types of objects using the same construction process. It provides clear methods for setting optional parameters.

4. Real-World Use Cases

1. Creating a complex meal with multiple courses (starter, main course, dessert, drink).

2. Constructing a detailed report with sections that can be customized (title, header, footer, body).

5. Implementation Steps

1. Specify an abstract interface for creating parts of the product object.

2. Implement concrete builders for specific types of products, adhering to the builder interface.

3. Define a director class to construct the product using the builder object.

4. The client will use both the director and the builder to create the desired product.

6. Implementation in JavaScript

// Builder interface
class UserProfileBuilder {
  setName(name) {}
  setAge(age) {}
  setAddress(address) {}
  setPhone(phone) {}
  getResult() {}
}
// Concrete builder
class ConcreteUserProfileBuilder extends UserProfileBuilder {
  constructor() {
    super();
    this.userProfile = {};
  }
  setName(name) {
    this.userProfile.name = name;
    return this; // allow for chaining
  }
  setAge(age) {
    this.userProfile.age = age;
    return this; // allow for chaining
  }
  setAddress(address) {
    this.userProfile.address = address;
    return this; // allow for chaining
  }
  setPhone(phone) {
    this.userProfile.phone = phone;
    return this; // allow for chaining
  }
  getResult() {
    return this.userProfile;
  }
}
// Director
class UserProfileDirector {
  constructor(builder) {
    this.builder = builder;
  }
  construct(name, age, address, phone) {
    this.builder.setName(name).setAge(age).setAddress(address).setPhone(phone);
  }
}
// Client code
const builder = new ConcreteUserProfileBuilder();
const director = new UserProfileDirector(builder);
director.construct("John Doe", 25, "123 Main St", "123-456-7890");
const userProfile = builder.getResult();
console.log(userProfile);

Output:

{
  name: "John Doe",
  age: 25,
  address: "123 Main St",
  phone: "123-456-7890"
}

Explanation:

1. UserProfileBuilder is the abstract builder interface with methods to construct parts of the product.

2. ConcreteUserProfileBuilder is a concrete implementation that provides mechanisms to set details of a user profile.

3. The methods in the concrete builder return 'this' allowing for method chaining, making it easier to set multiple attributes.

4. UserProfileDirector uses a builder to construct a complete user profile.

5. The client code combines the director and the builder to create the desired user profile.

7. When to use?

The Builder pattern is useful when:

1. The algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled.

2. The construction process must allow different representations of the constructed object.

3. You want a clear separation between construction and representation of an object.

4. The object has many optional configurations or components.


Comments