Mark As Completed Discussion

Builder

The Builder pattern helps... well, build objects! It can be useful in two situations:

  • You have an object that could go in a variety of flavors.
  • An object uses a non-trivial, multi-step creation process.

When an object could go in a variety of flavors, a common solution is to use a constructor with many parameters that define whether each of these flavors should be used:

1// In JavaScript
2constructor(size, salami, mozzarella, ruccola) { }

An alternative solution is to use the Builder pattern where a separate builder class manages adding flavors to an object and provides methods that make adding flavors explicit.

In the code below, we have two classes: Pizza represents a pizza but isn't intended to be used to construct pizzas, and PizzaBuilder is there for the sole purpose of constructing a custom pizza with a set of possible flavors:

1class Pizza {
2    constructor(builder) {
3        this.size = builder.size;
4        this.salami = builder.salami;
5        this.mozzarella = builder.mozzarella;
6        this.ruccola = builder.ruccola;
7    }
8
9    getDescription() {
10        return `This is a ${this.size} cm pizza.`;
11    }
12}
13
14class PizzaBuilder {
15    constructor(size) {
16        this.size = size;
17        this.salami = false;
18        this.mozzarella = false;
19        this.ruccola = false;
20    }
21
22    addSalami() {
23        this.salami = true;
24        return this;
25    }
26
27    addMozzarella() {
28        this.mozzarella = true;
29        return this;
30    }
31
32    addRuccola() {
33        this.ruccola = true;
34        return this;
35    }
36
37    build() {
38        return new Pizza(this);
39    }
40}

At call site, we create a pizza via PizzaBuilder that makes the customization process very explicit:

1// In JavaScript
2const pizza = new PizzaBuilder(28)
3    .addMozzarella()
4    .addSalami()
5    .addRuccola()
6    .build();
7
8console.log(pizza.getDescription());

Note that many programming languages allow using named parameters on call sites, which can be a valid alternative to using the Builder pattern in some cases:

1var pizza = new Pizza(28, true, false, true);

However, if a builder goes beyond adding parameters to an object and applies custom logic on each step of object construction, then named parameters aren't a viable replacement.