1.2. Builder
1.2.1. Purpose
Builder is an interface that build parts of a complex object.
Sometimes, if the builder has a better knowledge of what it builds, thisinterface could be an abstract class with default methods (aka adapter).
If you have a complex inheritance tree for objects, it is logical tohave a complex inheritance tree for builders too.
Note: Builders have often a fluent interface, see the mock builder ofPHPUnit for example.
1.2.2. Examples
- PHPUnit: Mock Builder
1.2.3. UML Diagram
1.2.4. Code
You can also find this code on GitHub
Director.php
- <?php
- namespace DesignPatterns\Creational\Builder;
- use DesignPatterns\Creational\Builder\Parts\Vehicle;
- /**
- * Director is part of the builder pattern. It knows the interface of the builder
- * and builds a complex object with the help of the builder
- *
- * You can also inject many builders instead of one to build more complex objects
- */
- class Director
- {
- public function build(BuilderInterface $builder): Vehicle
- {
- $builder->createVehicle();
- $builder->addDoors();
- $builder->addEngine();
- $builder->addWheel();
- return $builder->getVehicle();
- }
- }
BuilderInterface.php
- <?php
- namespace DesignPatterns\Creational\Builder;
- use DesignPatterns\Creational\Builder\Parts\Vehicle;
- interface BuilderInterface
- {
- public function createVehicle();
- public function addWheel();
- public function addEngine();
- public function addDoors();
- public function getVehicle(): Vehicle;
- }
TruckBuilder.php
- <?php
- namespace DesignPatterns\Creational\Builder;
- use DesignPatterns\Creational\Builder\Parts\Vehicle;
- class TruckBuilder implements BuilderInterface
- {
- /**
- * @var Parts\Truck
- */
- private $truck;
- public function addDoors()
- {
- $this->truck->setPart('rightDoor', new Parts\Door());
- $this->truck->setPart('leftDoor', new Parts\Door());
- }
- public function addEngine()
- {
- $this->truck->setPart('truckEngine', new Parts\Engine());
- }
- public function addWheel()
- {
- $this->truck->setPart('wheel1', new Parts\Wheel());
- $this->truck->setPart('wheel2', new Parts\Wheel());
- $this->truck->setPart('wheel3', new Parts\Wheel());
- $this->truck->setPart('wheel4', new Parts\Wheel());
- $this->truck->setPart('wheel5', new Parts\Wheel());
- $this->truck->setPart('wheel6', new Parts\Wheel());
- }
- public function createVehicle()
- {
- $this->truck = new Parts\Truck();
- }
- public function getVehicle(): Vehicle
- {
- return $this->truck;
- }
- }
CarBuilder.php
- <?php
- namespace DesignPatterns\Creational\Builder;
- use DesignPatterns\Creational\Builder\Parts\Vehicle;
- class CarBuilder implements BuilderInterface
- {
- /**
- * @var Parts\Car
- */
- private $car;
- public function addDoors()
- {
- $this->car->setPart('rightDoor', new Parts\Door());
- $this->car->setPart('leftDoor', new Parts\Door());
- $this->car->setPart('trunkLid', new Parts\Door());
- }
- public function addEngine()
- {
- $this->car->setPart('engine', new Parts\Engine());
- }
- public function addWheel()
- {
- $this->car->setPart('wheelLF', new Parts\Wheel());
- $this->car->setPart('wheelRF', new Parts\Wheel());
- $this->car->setPart('wheelLR', new Parts\Wheel());
- $this->car->setPart('wheelRR', new Parts\Wheel());
- }
- public function createVehicle()
- {
- $this->car = new Parts\Car();
- }
- public function getVehicle(): Vehicle
- {
- return $this->car;
- }
- }
Parts/Vehicle.php
- <?php
- namespace DesignPatterns\Creational\Builder\Parts;
- abstract class Vehicle
- {
- /**
- * @var object[]
- */
- private $data = [];
- /**
- * @param string $key
- * @param object $value
- */
- public function setPart($key, $value)
- {
- $this->data[$key] = $value;
- }
- }
Parts/Truck.php
- <?php
- namespace DesignPatterns\Creational\Builder\Parts;
- class Truck extends Vehicle
- {
- }
Parts/Car.php
- <?php
- namespace DesignPatterns\Creational\Builder\Parts;
- class Car extends Vehicle
- {
- }
Parts/Engine.php
- <?php
- namespace DesignPatterns\Creational\Builder\Parts;
- class Engine
- {
- }
Parts/Wheel.php
- <?php
- namespace DesignPatterns\Creational\Builder\Parts;
- class Wheel
- {
- }
Parts/Door.php
- <?php
- namespace DesignPatterns\Creational\Builder\Parts;
- class Door
- {
- }
1.2.5. Test
Tests/DirectorTest.php
- <?php
- namespace DesignPatterns\Creational\Builder\Tests;
- use DesignPatterns\Creational\Builder\Parts\Car;
- use DesignPatterns\Creational\Builder\Parts\Truck;
- use DesignPatterns\Creational\Builder\TruckBuilder;
- use DesignPatterns\Creational\Builder\CarBuilder;
- use DesignPatterns\Creational\Builder\Director;
- use PHPUnit\Framework\TestCase;
- class DirectorTest extends TestCase
- {
- public function testCanBuildTruck()
- {
- $truckBuilder = new TruckBuilder();
- $newVehicle = (new Director())->build($truckBuilder);
- $this->assertInstanceOf(Truck::class, $newVehicle);
- }
- public function testCanBuildCar()
- {
- $carBuilder = new CarBuilder();
- $newVehicle = (new Director())->build($carBuilder);
- $this->assertInstanceOf(Car::class, $newVehicle);
- }
- }