Строитель (Builder) паттерн

Отредачено 11.06.2025,
а чекнуто 443 💁

Это один из самых недооценённых, но мощных паттернов, особенно когда нужно конструировать сложные объекты пошагово. Сейчас всё разложу по полочкам, примеры — на Laravel + PHP 8.3.

Суть

Builder позволяет создавать сложные объекты поэтапно, а не через перегруженный конструктор или кучу set-методов. Он изолирует процесс построения объекта от его конечной репрезентации.


🔧 Когда применять

  • Объект состоит из множества параметров, не все из которых обязательны;

  • Нужно разные представления одного и того же объекта;

  • Нужно собирать объект поэтапно — особенно если сборка зависит от условий;

  • Нужен чистый код, без "спагетти" из ifnewset*() и т.п.


📦 Laravel-пример: Генератор отчёта

Ты делаешь модуль для генерации отчёта (PDF, HTML, JSON), и в зависимости от параметров ты:

  • подгружаешь данные;

  • добавляешь фильтры;

  • применяешь форматирование;

  • указываешь вывод.

 

Класс отчёта

class Report
{
    public string $title;
    public array $filters = [];
    public array $data = [];
    public string $format;

    public function output(): string
    {
        // простая симуляция вывода
        return "{$this->format} Report: {$this->title}";
    }
}

 

Интерфейс строителя

interface ReportBuilderInterface
{
    public function setTitle(string $title): static;
    public function setFilters(array $filters): static;
    public function setData(array $data): static;
    public function setFormat(string $format): static;
    public function getReport(): Report;
}

 

Конкретный строитель

class ReportBuilder implements ReportBuilderInterface
{
    protected Report $report;

    public function __construct()
    {
        $this->report = new Report();
    }

    public function setTitle(string $title): static
    {
        $this->report->title = $title;
        return $this;
    }

    public function setFilters(array $filters): static
    {
        $this->report->filters = $filters;
        return $this;
    }

    public function setData(array $data): static
    {
        $this->report->data = $data;
        return $this;
    }

    public function setFormat(string $format): static
    {
        $this->report->format = strtoupper($format);
        return $this;
    }

    public function getReport(): Report
    {
        return $this->report;
    }
}

 

Использование строителя

$builder = new ReportBuilder();

$report = $builder
    ->setTitle('Monthly Sales')
    ->setFilters(['region' => 'EU'])
    ->setData([/* данные из БД */])
    ->setFormat('pdf')
    ->getReport();

echo $report->output(); // PDF Report: Monthly Sales

 

С добавлением "директора" (по желанию)

Иногда добавляют Director — сущность, которая управляет сценарием сборки:

class ReportDirector
{
    public function buildSalesReport(ReportBuilderInterface $builder): Report
    {
        return $builder
            ->setTitle('Sales Report')
            ->setFilters(['year' => date('Y')])
            ->setData([/* ... */])
            ->setFormat('html')
            ->getReport();
    }
}

 

Laravel-стиль и практика

  • Очень удобно использовать в формировании email-уведомленийэкспорта CSV/XLSконфигурации API-запросовсоздания сложных DTO.

  • Можно внедрять Builder через контейнер Laravel, если он зависит от других сервисов.

  • Совместим с Fluent-интерфейсом ($builder->setX()->setY()) — удобно и читаемо.

 

Отличие от фабрики

Фабрика Строитель
Создает объект за один шаг Создает объект пошагово
Фокус на типе Фокус на процессе
Одна функция make() Много шагов setX()setY()
Пример: PaymentGatewayFactory Пример: ReportBuilder

 

Когда НЕ стоит использовать

❌ Когда объект простой (new User() и достаточно).
❌ Когда количество шагов фиксировано и без условий.

ООП Паттерны проектирования