Строитель (Builder) паттерн
Это один из самых недооценённых, но мощных паттернов, особенно когда нужно конструировать сложные объекты пошагово. Сейчас всё разложу по полочкам, примеры — на Laravel + PHP 8.3.
Суть
Builder позволяет создавать сложные объекты поэтапно, а не через перегруженный конструктор или кучу set-методов. Он изолирует процесс построения объекта от его конечной репрезентации.
🔧 Когда применять
-
Объект состоит из множества параметров, не все из которых обязательны;
-
Нужно разные представления одного и того же объекта;
-
Нужно собирать объект поэтапно — особенно если сборка зависит от условий;
-
Нужен чистый код, без "спагетти" из
if,new,set*()и т.п.
📦 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() и достаточно).
❌ Когда количество шагов фиксировано и без условий.