Introduction to Builder design pattern in PHP
By admin
The Builder Pattern is a software design pattern which helps to simplify creation of complex objects by reducing the number of parameters in the object constructor.
This pattern uses a builder object to collect parameters of the complex object and return the final constructed object.
Problem:
Imagine we have a car object with many attributes.
The following is the class definition and object instantiation code:
<pre class="lang:php decode:true">class Car {
protected $make;
protected $model;
protected $badge;
protected $series;
protected $year;
protected $kilometers;
protected $bodyType;
protected $engineSize;
protected $fuelType;
protected $cylinders;
protected $transmission;
protected $color;
public function __construct($make, $model, $badge, $series, $year, $kilometers, $bodyType, $engineSize,
$fuelType, $cylinders, $transmission, $color) {
$this->make = $make;
$this->model = $model;
$this->badge = $badge;
$this->series = $series;
$this->year = $year;
$this->kilometers = $kilometers;
$this->bodyType = $bodyType;
$this->engineSize = $engineSize;
$this->fuelType = $fuelType;
$this->cylinders = $cylinders;
$this->transmission = $transmission;
$this->color = $color;
}
}
$carObj = new car('Toyota', 'Camry', 'Altise', 'ACV36R', '2005', '60000', 'Sedan', '2400', 'Petrol', '4', 'Auto', 'White');
var_dump($carObj);
As you can see everything we want to create a Car object we have to pass all those attribute to the constructor.
In addition, What if we want to skip over some attributes and use the default value? For instance, we want to have default value of ‘Sedan’, ‘Petrol’, and ‘4’ for bodyType, fuelType, and cylinders respectively.
The constructor would look like :
<pre class="lang:php decode:true " title="short title">public function __construct($make, $model, $badge, $series, $year, $kilometers, $bodyType = 'Sedan', $engineSize, $fuelType = 'Petrol', $cylinders = 4, $transmission, $color) { ... }
But how would our object instantiation look like?
Solution: Builder Pattern
Instead of instantiating Car object directly we create a builder object called CarBuilder and let that handle our object creation:
<pre class="lang:php decode:true ">class CarBuilder {
protected $make;
protected $model;
protected $badge;
protected $series;
protected $year;
protected $kilometers;
protected $bodyType = 'Sedan';
protected $engineSize;
protected $fuelType = 'Petrol';
protected $cylinders = 4;
protected $transmission;
protected $color;
public function __construct() { }
public function setMake($make)
{
$this->make = $make;
return $this;
}
public function setModel($model)
{
$this->model = $model;
return $this;
}
public function setBadge($badge)
{
$this->badge = $badge;
return $this;
}
public function setSeries($series)
{
$this->series = $series;
return $this;
}
public function setYear($year)
{
$this->year = $year;
return $this;
}
public function setKilometers($kilometers)
{
$this->kilometers = $kilometers;
return $this;
}
public function setBodyType($bodyType)
{
$this->bodyType = $bodyType;
return $this;
}
public function setEngineSize($engineSize)
{
$this->engineSize = $engineSize;
return $this;
}
public function setFuelType($fuelType)
{
$this->fuelType = $fuelType;
return $this;
}
public function setCylinders($cylinders)
{
$this->cylinders = $cylinders;
return $this;
}
public function setTransmission($transmission)
{
$this->transmission = $transmission;
return $this;
}
public function setColor($color)
{
$this->color = $color;
return $this;
}
public function build()
{
return new Car($this->make, $this->model, $this->badge, $this->series, $this->year, $this->kilometers, $this->bodyType,
$this->engineSize, $this->fuelType, $this->cylinders, $this->transmission, $this->color);
}
}
$builderObj = new CarBuilder();
$carObj = $builderObj->setMake('Toyota')
->setModel('Camry')
->setBadge('Altise')
->setSeries('ACV36R')
->setYear('2005')
->setKilometers('60000')
->setEngineSize('2400')
->setTransmission('Auto')
->setColor('White')
->build();
var_dump($carObj);
Advantages:
- Clean and easier to read code
- Decoupled and more encapsulated code (have you noticed the use of Factory Pattern inside build() function?)
- You can easily skip attributes that are not needed for specific objects and use the default value instead.
- Avoiding too many arguments in the constructor
Disadvantages:
- It requires writing more code