What is the Builder Pattern?
The principle is to collect all the necessary components first. Once all the parts are there, the object can be built. Here is an example that creates an instance of the "Coffee" class in the conventional way and also via Builder:
// Erzeugung einer Instanz auf 'normale' Art let manualyCreatedCoffee = new Coffee(200, 20, 1); manualyCreatedCoffee.print(); // Water: 200 Milk: 20 Sugar: 1 // Erzeugung einer Instanz auf "Builder" Art let coffee = new Coffee.CoffeeBuilder() .withSugar(2) .withWater(200) .withMilk(0) .build(); coffee.print(); // Water: 200 Milk: 0 Sugar: 2 let espresso = new Coffee.CoffeeBuilder() .espresso() .withSugar(1) .build(); espresso.print(); // Water: 50 Milk: 0 Sugar: 1
And here is the definition of the class
// Klasse die Attribute für einen Kaffee enthält
class Coffee {
#water
#sugar
#milk
constructor(water, milk, sugar) {
this.#water = water;
this.#milk = milk;
this.#sugar = sugar;
}
print() {
console.log("Water:", this.#water, "Milk:", this.#milk, "Sugar:", this.#sugar);
}
// Hier wird ein Builder definiert (muss nicht Teil der Klasse sein)
static CoffeeBuilder = class {
#water = 0
#milk = 0
#sugar = 0
// Methoden um einzelne Attribute zu setzen
withWater(waterInMl) {
this.#water = waterInMl;
return this; // Gibt die Builder Instanz zurück. So können die Einstellungen aneinander gekettet werden.
}
withMilk(milkInMl) {
this.#milk = milkInMl;
return this;
}
withSugar(cubes) {
this.#sugar = cubes;
return this;
}
// Methoden, die mehrere Attribute setzen - wie presets für einen Kaffee
normal() {
this.#water = 200;
this.#milk = 0;
this.#sugar = 0;
return this;
}
espresso() {
this.#water = 50;
this.#milk = 0;
this.#sugar = 0;
return this;
}
// Erst bei build wird der eigentliche Kaffee erzeugt
build() {
// Hier könnte man auch validieren, ob alle Attribute valide sind
return new Coffee(this.#water, this.#milk, this.#sugar);
}
}
}
In this small example, we can already see the following positive features of the builder:
- The creation of the objects is more speaking/readable
- A validation could be built in so that only valid coffees can be created
- If you have many attributes for an object, they can be used more easily via the builder (especially if optional parameters are involved)
- More complex settings can be stored with 'Presets'. For example, if we were to add a brewing pressure to the object, the presets can be extended by the default value. This means that the 'complex' object can also be used by non-professionals (How much brewing pressure do I need for an espresso?).
Builder Pattern GoF
The builder pattern shown is actually a very strong simplification of the builder pattern defined by the Gang of Four (GoF). However, this is often what is meant. The example shown here could be transferred to the 'original' (vending machine):
- We can create various objects with the same steps:
- Step 1: Add powder, Step 2: Add water, Step 3: Mix ingredients, Step 4: Finished product
- A "director" knows these steps, he just needs to know who (builder) should carry them out
- e.g. CoffeeBuilder, CacaoBuilder, TeaBuilder
- A "Client" tells the "Director" which "Builder" is to be used. The director calls up the individual steps on this.
- The result is either coffee, cocoa or tea
Conclusion
You should use the pattern if it provides an advantage: If you have complex objects to create, this is a very good way to simplify the creation. Also check whether your IDE can help you create the builder.



