Коротка відповідь
middleBuilder — це паттерн, що розділяє побудову складного об’єкта від його представлення, дозволяючи створювати різні варіанти однієї структури. У TS це реалізується через інтерфейс Builder, конкретний клас ConcreteBuilder і Director, який послідовно викликає методи побудови. Наприклад: `builder.setEngine('V8').setWheels(4).build();`
Повне пояснення
1. Що це і навіщо
Builder — паттерн створення, що дозволяє поетапно конструювати складний об’єкт, розділяючи процес побудови від кінцевого представлення. Підходить для створення об’єктів з багатьма параметрами, де потрібна гнучкість у виборі конфігурації.
2. Принцип роботи / алгоритм
- Director керує послідовністю викликів методів Builder.
- Builder (інтерфейс) визначає набори операцій:
setPartA(),setPartB()тощо. - ConcreteBuilder реалізує ці методи, зберігаючи внутрішню модель.
- Після завершення побудови викликається
build()для отримання готового об’єкта.
3. Реалізація (JS / TS)
- Базова реалізація
interface CarBuilder {
setEngine(engine: string): this;
setWheels(count: number): this;
build(): Car;
}
class SportsCarBuilder implements CarBuilder {
private car = new Car();
setEngine(engine: string) { this.car.engine = engine; return this; }
setWheels(count: number) { this.car.wheels = count; return this; }
build() { return this.car; }
}
- Реалістичний приклад (Node.js API)
class UserBuilder {
private user: Partial<User> = {};
setName(name: string) { this.user.name = name; return this; }
setEmail(email: string) { this.user.email = email; return this; }
async build() {
const newUser = await UserModel.create(this.user as User);
return newUser;
}
}
// Usage
const user = await new UserBuilder().setName('Alice').setEmail('a@b.com').build();
- Спрощений для новачка (React компонент)
class ButtonBuilder {
private props: any = {};
setLabel(label: string) { this.props.label = label; return this; }
setColor(color: string) { this.props.style = { color }; return this; }
build() { return <button {...this.props} />; }
}
const btn = new ButtonBuilder().setLabel('Click').setColor('red').build();
4. Тестування (Jest або Vitest)
test('Builder creates car with correct parts', () => {
const builder = new SportsCarBuilder();
const car = builder.setEngine('V8').setWheels(4).build();
expect(car.engine).toBe('V8');
expect(car.wheels).toBe(4);
});
5. Проблеми та edge cases
- Неправильне використання ролей – Director викликає методи в неправильному порядку, що призводить до неповного об’єкта.
- Зайва абстракція – Builder створюється лише для простих об’єктів, що збільшує складність без вигоди.
- Cyclical dependencies – Builder залежить від конкретного продукту, а продукт залежить від Builder.
- Плутанина між паттернами – Builder vs Factory Method: Builder для складних об’єктів, Factory для простих.
- Performance‑пастки – Часті створення проміжних об’єктів у Builder може збільшити GC‑нагрузку.
6. Оптимізація та продуктивність
- Builder мінімізує кількість конструкторів, що зменшує код‑швидкість компіляції.
- Використання fluent API з
thisдозволяє уникнути створення тимчасових об’єктів. - У великих проектах Builder може бути замінений на Record‑based factory для зменшення пам’яті.
7. Без JS / архітектурні альтернативи
- У чистій HTML/CSS можна розділити шаблон (template) і дані, використовуючи
data-атрибути. - У серверних мовах без паттернів можна просто передавати об’єкт конфігурації в конструктор.
8. Cheatsheet + follow-up
- Cheatsheet:
Director → Builder → Product. Fluent API:builder.setA().setB().build(). - Interview Q1: Як Builder відрізняється від Factory Method?
- Interview Q2: Які переваги має fluent API в Builder‑паттерні?