Что это такое
Паттерн Builder («строитель») создаёт сложный объект шаг за шагом. Вместо одного конструктора с длинным и непонятным списком аргументов строитель предлагает небольшие именованные шаги — и финальный build(), который возвращает готовый объект.
Каждый шаг возвращает сам строитель, поэтому вызовы соединяются в цепочку и читаются как предложение.
Пример: собираем пиццу
Сравните new PizzaBuilder("большая").cheese().topping("грибы") с конструктором вида new Pizza("большая", true, ["грибы"]) — строитель говорит, что означает каждое значение, а необязательные части просто пропускаются.
Шаги, которые соединяются в цепочку
Каждый шаг имеет имя и не обязателен: маленькая пицца пропускает их все и получается с cheese: false и пустым списком добавок. Никакой каши из аргументов true, undefined, false.
Вывод: программа на TypeScript и захваченный вывод
interface Pizza {
size: string
cheese: boolean
toppings: string[]
}
class PizzaBuilder {
private pizza: Pizza
constructor(size: string) {
this.pizza = { size: size, cheese: false, toppings: [] }
}
// Каждый шаг возвращает сам строитель, поэтому вызовы объединяются в цепочку.
cheese(): PizzaBuilder {
this.pizza.cheese = true
return this
}
topping(name: string): PizzaBuilder {
this.pizza.toppings.push(name)
return this
}
build(): Pizza {
return this.pizza
}
}
function describe(p: Pizza): string {
return `пицца (${p.size}), сыр: ${p.cheese}, добавки: [${p.toppings.join(", ")}]`
}
const big = new PizzaBuilder("большая")
.cheese()
.topping("грибы")
.topping("оливки")
.build()
const small = new PizzaBuilder("маленькая").build()
console.log(describe(big))
console.log(describe(small))
Когда это использовать
Используйте, когда у объекта много необязательных частей или когда создание состоит из настоящих шагов, которые заслуживают имён. Запросы, выборки и конфигурации — классическая территория строителя.
Не используйте для простых объектов — объектный литерал с именованными свойствами, { size: "большая", cheese: true, toppings: [] }, уже вполне хороший маленький строитель для лёгких случаев.
Плюсы и минусы
Плюсы: читаемое создание объекта; необязательные части без огромных списков аргументов; объект можно проверить один раз, в build().
Минусы: ещё один класс, который надо написать и поддерживать; излишество там, где объектный литерал и так хорошо читается.