Будівельник (Builder)
Аналогія
Допустимо, ви прийшли в забігайлівку, замовили бургер дня, і вам видали його без запитань. Це приклад «Проста фабрика». Але іноді логіка створення складається з більшої кількості кроків. Наприклад, при замовленні бургера є кілька варіантів хліба, начинки, соусів, додаткових інгредієнтів. У таких ситуаціях допомагає шаблон Будівник.
Коротко
Шаблон дозволяє створювати різні характеристики об'єкта, уникаючи забруднення конструктора (constructor pollution). Це корисно, коли об'єкт може мати кілька властивостей. Або коли створення об'єкта складається з великої кількості етапів.
Вікіпедія
Шаблон "Будівельник" призначений для пошуку вирішення проблеми антипаттерну Telescoping constructor.
Поясню, що таке антипаттер Telescoping constructor. Кожен із нас коли-небудь стикався з подібним конструктором:
public function __construct($size, $cheese = true, $pepperoni = true, $tomato = false, $lettuce = true)
{
}
Як бачите, кількість параметрів може швидко розростись, і важко буде розібратися в їх структурі. Крім того, цей список параметрів зростатиме і надалі, якщо в майбутньому ви захочете додати нові опції. Це і є антіпаттерн Telescoping constructor.
Приклад
Розумна альтернатива – шаблон «Будівельник». Спочатку створимо бургер:
class Burger
{
protected $size;
protected $cheese = false;
protected $pepperoni = false;
protected $lettuce = false;
protected $ tomato = false;
public function __construct(BurgerBuilder $builder)
{
$this->size = $builder->size;
$this->cheese = $builder->cheese;
$this->pepperoni = $builder->pepperoni;
$this->lettuce = $builder->lettuce;
$this->tomato = $builder->tomato;
}
}
А потім додамо «будівника»:
class BurgerBuilder
{
public $size;
public $cheese = false;
public $ pepperoni = false;
$lettuce = false;
public $ tomato = false;
public function __construct(int $size)
{
$this->size = $size;
}
public function addPepperoni()
{
$this->pepperoni = true;
return $this;
}
public function addLettuce()
{
$this->lettuce = true;
return $this;
}
public function addCheese()
{
$this->cheese = true;
return $this;
}
public function addTomato()
{
$this->tomato = true;
return $this;
}
public function build(): Burger
{
return new Burger($this);
}
}
Використання:
$burger = (new BurgerBuilder(14))
->addPepperoni()
->addLettuce()
->addTomato()
->build();
Коли використовувати?
Коли об'єкт може мати кілька властивостей і коли потрібно уникнути Telescoping constructor. Ключова відмінність від шаблону "Проста фабрика": він використовується в одноетапному створенні, а "Будівельник" - у багатоетапному.