Ответ
Паттерн Builder отделяет конструирование сложного объекта от его представления, позволяя создавать разные представления объекта, используя один и тот же процесс построения.
Классическая реализация (из GoF):
// 1. Продукт, который мы строим
class Car
{
private string $engine = '';
private int $seats = 0;
private bool $hasGPS = false;
private bool $hasTripComputer = false;
public function setEngine(string $engine): void { $this->engine = $engine; }
public function setSeats(int $seats): void { $this->seats = $seats; }
public function setGPS(bool $hasGPS): void { $this->hasGPS = $hasGPS; }
public function setTripComputer(bool $hasTripComputer): void { $this->hasTripComputer = $hasTripComputer; }
public function getDescription(): string
{
return sprintf(
"Car with %s engine, %d seats%s%s.",
$this->engine,
$this->seats,
$this->hasGPS ? ', GPS' : '',
$this->hasTripComputer ? ', Trip Computer' : ''
);
}
}
// 2. Интерфейс Строителя
interface CarBuilder
{
public function reset(): void;
public function buildEngine(): void;
public function buildSeats(): void;
public function buildGPS(): void;
public function buildTripComputer(): void;
public function getResult(): Car;
}
// 3. Конкретный строитель для спортивного автомобиля
class SportsCarBuilder implements CarBuilder
{
private Car $car;
public function reset(): void { $this->car = new Car(); }
public function buildEngine(): void { $this->car->setEngine('V8 Turbo'); }
public function buildSeats(): void { $this->car->setSeats(2); }
public function buildGPS(): void { $this->car->setGPS(true); } // В спортивной версии есть GPS
public function buildTripComputer(): void { $this->car->setTripComputer(true); }
public function getResult(): Car { return $this->car; }
}
// 4. Директор, который управляет процессом построения
class Director
{
public function constructSportsCar(CarBuilder $builder): Car
{
$builder->reset();
$builder->buildEngine();
$builder->buildSeats();
$builder->buildGPS();
$builder->buildTripComputer();
return $builder->getResult();
}
}
// 5. Клиентский код
$builder = new SportsCarBuilder();
$director = new Director();
$car = $director->constructSportsCar($builder);
echo $car->getDescription(); // Car with V8 Turbo engine, 2 seats, GPS, Trip Computer.
Почему это полезно:
- Изоляция сложной логики создания. Клиент (
Director) не знает деталей сборки конкретной модели. - Гибкость. Можно легко добавить нового строителя для
SUVBuilderс другим набором опций, используя тот же интерфейс. - Пошаговое конструирование. Методы
build...можно вызывать в разном порядке или пропускать, если это позволяет строитель.
Ответ 18+ 🔞
Слушай, а вот Builder — это вообще огонь паттерн, когда тебе надо собрать какую-нибудь пиздопроебибну конструкцию по кирпичикам. Представь, ты не просто new Car() и в него двадцать сеттеров пихаешь, а у тебя есть чёткий план, какого хуя и в каком порядке собирать.
Вот смотри, классика жанра, прямо из умных книжек.
Разбираем по косточкам:
// 1. Это наш конечный продукт, который мы будем собирать
class Car
{
private string $engine = '';
private int $seats = 0;
private bool $hasGPS = false;
private bool $hasTripComputer = false;
public function setEngine(string $engine): void { $this->engine = $engine; }
public function setSeats(int $seats): void { $this->seats = $seats; }
public function setGPS(bool $hasGPS): void { $this->hasGPS = $hasGPS; }
public function setTripComputer(bool $hasTripComputer): void { $this->hasTripComputer = $hasTripComputer; }
public function getDescription(): string
{
return sprintf(
"Car with %s engine, %d seats%s%s.",
$this->engine,
$this->seats,
$this->hasGPS ? ', GPS' : '',
$this->hasTripComputer ? ', Trip Computer' : ''
);
}
}
Продукт — он как есть. Просто коробка с полями и сеттерами. Доверия ебать ноль — сам по себе он нихрена не умеет.
// 2. А вот это — контракт для всех строителей. Инструкция, блядь.
interface CarBuilder
{
public function reset(): void;
public function buildEngine(): void;
public function buildSeats(): void;
public function buildGPS(): void;
public function buildTripComputer(): void;
public function getResult(): Car;
}
Интерфейс говорит: хочешь быть строителем — умей делать вот эти пять действий. Не умеешь — иди ты нахуй, не строитель ты.
// 3. А вот конкретный чувак, который знает, как собрать тачку для гонок
class SportsCarBuilder implements CarBuilder
{
private Car $car;
public function reset(): void { $this->car = new Car(); }
public function buildEngine(): void { $this->car->setEngine('V8 Turbo'); } // Двигатель — чтоб сосалки обзавидовались
public function buildSeats(): void { $this->car->setSeats(2); } // Места только для водилы и тёлки
public function buildGPS(): void { $this->car->setGPS(true); } // Нафиг ему GPS? А хуй его знает, но в комплектации есть!
public function buildTripComputer(): void { $this->car->setTripComputer(true); }
public function getResult(): Car { return $this->car; }
}
Этот парень — специалист. Он не будет ставить движок от трактора или шесть сидений. Он чётко знает рецепт спортивного болида.
// 4. А это — прораб, начальник стройки. Он командует, что делать.
class Director
{
public function constructSportsCar(CarBuilder $builder): Car
{
$builder->reset(); // Начинаем с чистого листа
$builder->buildEngine(); // Сперва движок, основа основ
$builder->buildSeats(); // Потом сидушки
$builder->buildGPS(); // Потом навигацию
$builder->buildTripComputer(); // И наконец бортовик
return $builder->getResult(); // Всё, забирай готовое!
}
}
Директору да похуй, какой именно строитель пришёл — спортивный или внедорожный. Он тыкает пальцем в интерфейс и говорит: «Делай раз, делай два!». А тот уж сам знает, как именно делать.
// 5. Ну и мы, клиенты, которые всё это запускаем
$builder = new SportsCarBuilder();
$director = new Director();
$car = $director->constructSportsCar($builder);
echo $car->getDescription(); // Car with V8 Turbo engine, 2 seats, GPS, Trip Computer.
И вуаля! Мы получили тачку, даже не вникая, какой там хуй с винтом внутри у SportsCarBuilder.
В чём, блядь, соль?
- Сложность спрятана. Клиенту (нам) не нужно знать, что спорткар собирается в другом порядке или с другими деталями, чем внедорожник. Волнение ебать — ноль. Прораб всё сделает.
- Гибкость — овердохуища. Захотел грузовик — написал
TruckBuilder, который ставит дизель и десять колёс. Прораб (Director) будет работать с ним по той же самой схеме, тыкая в те же методыbuildEngine()иbuildSeats(). Ёпта, красота! - Контроль над процессом. Можно собирать пошагово, можно пропускать шаги (если строитель позволяет). Хочешь тачку без GPS — просто не вызывай
buildGPS(). Всё в твоих руках, чувак.
Короче, если объект — манда с ушами, с кучей опций и вариаций сборки, Builder — твой выбор. Не надо городить один хуй в пальто-конструктор на все случаи жизни.