Creational

Builder

Builder pulls the step-by-step assembly of a complex object out into a separate object, so the same sequence of steps can produce different finished configurations of that object.

Complexity
Popularity

Problem

A `House` object needs a wall count, a door count, a window count, and optional extras like a roof or a garage - most of which are optional and many of which depend on each other. A constructor covering every combination either explodes into `new House(walls, doors, windows, hasRoof, hasGarage, ...)` with half the arguments set to defaults nobody remembers the order of, or it multiplies into a subclass for every popular layout: `SimpleFourWallHouse`, `FamilyHouseWithGarage`, and so on, which stops scaling the moment a client wants something slightly different.

Both escape routes trade one problem for another: an unreadable, error-prone giant constructor, or a subclass explosion that still can't cover every custom layout.

Solution

Move the assembly logic into a separate builder object that exposes one method per configurable part - `buildWalls()`, `buildDoors()`, `buildWindows()`, `buildRoof()`, `buildGarage()` - each returning the builder itself so calls can be chained. The caller invokes only the steps relevant to a particular house and skips the rest; there's no giant parameter list to fill in blanks for.

Different builder classes implementing the same step interface can assemble entirely different representations from the same sequence of calls - a `HouseBuilder` and a `HouseBlueprintBuilder` could both consume the same steps but produce a livable house object versus a printable blueprint. When a handful of standard layouts are ordered often, a separate Director object can encode those recipes as fixed sequences of builder calls (`buildSimpleHouse()`, `buildFamilyHouse()`), while ad-hoc houses still go straight through the builder without a director at all.

When to Use

  • Reach for it when a constructor would need many optional parameters and most calls would only set a handful of them.
  • Reach for it when the same underlying construction process needs to yield visibly different end results depending on which builder or steps are used.
  • Reach for it when assembling an object involves ordering constraints or nested sub-objects that are easier to express as discrete steps than as one call.

Real-World Examples

  • **`fetch`/`Request` construction via chained config objects and libraries like `axios`** - request options accumulate through method calls or merged config before the actual network call fires.
  • **`StringBuilder` in Java and `StringBuilder`/template literals in .NET** - long strings are assembled through repeated `append()` calls instead of costly repeated concatenation.
  • **Query builders in ORMs like Knex.js and TypeORM** - `.select().where().orderBy().limit()` chains assemble a SQL query step by step before it's compiled and executed.