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

Alt Builder UML Diagram

1.2.4. Code

You can also find this code on GitHub

Director.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Creational\Builder;
  4.  
  5. use DesignPatterns\Creational\Builder\Parts\Vehicle;
  6.  
  7. /**
  8. * Director is part of the builder pattern. It knows the interface of the builder
  9. * and builds a complex object with the help of the builder
  10. *
  11. * You can also inject many builders instead of one to build more complex objects
  12. */
  13. class Director
  14. {
  15. public function build(BuilderInterface $builder): Vehicle
  16. {
  17. $builder->createVehicle();
  18. $builder->addDoors();
  19. $builder->addEngine();
  20. $builder->addWheel();
  21.  
  22. return $builder->getVehicle();
  23. }
  24. }

BuilderInterface.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Creational\Builder;
  4.  
  5. use DesignPatterns\Creational\Builder\Parts\Vehicle;
  6.  
  7. interface BuilderInterface
  8. {
  9. public function createVehicle();
  10.  
  11. public function addWheel();
  12.  
  13. public function addEngine();
  14.  
  15. public function addDoors();
  16.  
  17. public function getVehicle(): Vehicle;
  18. }

TruckBuilder.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Creational\Builder;
  4.  
  5. use DesignPatterns\Creational\Builder\Parts\Vehicle;
  6.  
  7. class TruckBuilder implements BuilderInterface
  8. {
  9. /**
  10. * @var Parts\Truck
  11. */
  12. private $truck;
  13.  
  14. public function addDoors()
  15. {
  16. $this->truck->setPart('rightDoor', new Parts\Door());
  17. $this->truck->setPart('leftDoor', new Parts\Door());
  18. }
  19.  
  20. public function addEngine()
  21. {
  22. $this->truck->setPart('truckEngine', new Parts\Engine());
  23. }
  24.  
  25. public function addWheel()
  26. {
  27. $this->truck->setPart('wheel1', new Parts\Wheel());
  28. $this->truck->setPart('wheel2', new Parts\Wheel());
  29. $this->truck->setPart('wheel3', new Parts\Wheel());
  30. $this->truck->setPart('wheel4', new Parts\Wheel());
  31. $this->truck->setPart('wheel5', new Parts\Wheel());
  32. $this->truck->setPart('wheel6', new Parts\Wheel());
  33. }
  34.  
  35. public function createVehicle()
  36. {
  37. $this->truck = new Parts\Truck();
  38. }
  39.  
  40. public function getVehicle(): Vehicle
  41. {
  42. return $this->truck;
  43. }
  44. }

CarBuilder.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Creational\Builder;
  4.  
  5. use DesignPatterns\Creational\Builder\Parts\Vehicle;
  6.  
  7. class CarBuilder implements BuilderInterface
  8. {
  9. /**
  10. * @var Parts\Car
  11. */
  12. private $car;
  13.  
  14. public function addDoors()
  15. {
  16. $this->car->setPart('rightDoor', new Parts\Door());
  17. $this->car->setPart('leftDoor', new Parts\Door());
  18. $this->car->setPart('trunkLid', new Parts\Door());
  19. }
  20.  
  21. public function addEngine()
  22. {
  23. $this->car->setPart('engine', new Parts\Engine());
  24. }
  25.  
  26. public function addWheel()
  27. {
  28. $this->car->setPart('wheelLF', new Parts\Wheel());
  29. $this->car->setPart('wheelRF', new Parts\Wheel());
  30. $this->car->setPart('wheelLR', new Parts\Wheel());
  31. $this->car->setPart('wheelRR', new Parts\Wheel());
  32. }
  33.  
  34. public function createVehicle()
  35. {
  36. $this->car = new Parts\Car();
  37. }
  38.  
  39. public function getVehicle(): Vehicle
  40. {
  41. return $this->car;
  42. }
  43. }

Parts/Vehicle.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Creational\Builder\Parts;
  4.  
  5. abstract class Vehicle
  6. {
  7. /**
  8. * @var object[]
  9. */
  10. private $data = [];
  11.  
  12. /**
  13. * @param string $key
  14. * @param object $value
  15. */
  16. public function setPart($key, $value)
  17. {
  18. $this->data[$key] = $value;
  19. }
  20. }

Parts/Truck.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Creational\Builder\Parts;
  4.  
  5. class Truck extends Vehicle
  6. {
  7. }

Parts/Car.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Creational\Builder\Parts;
  4.  
  5. class Car extends Vehicle
  6. {
  7. }

Parts/Engine.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Creational\Builder\Parts;
  4.  
  5. class Engine
  6. {
  7. }

Parts/Wheel.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Creational\Builder\Parts;
  4.  
  5. class Wheel
  6. {
  7. }

Parts/Door.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Creational\Builder\Parts;
  4.  
  5. class Door
  6. {
  7. }

1.2.5. Test

Tests/DirectorTest.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Creational\Builder\Tests;
  4.  
  5. use DesignPatterns\Creational\Builder\Parts\Car;
  6. use DesignPatterns\Creational\Builder\Parts\Truck;
  7. use DesignPatterns\Creational\Builder\TruckBuilder;
  8. use DesignPatterns\Creational\Builder\CarBuilder;
  9. use DesignPatterns\Creational\Builder\Director;
  10. use PHPUnit\Framework\TestCase;
  11.  
  12. class DirectorTest extends TestCase
  13. {
  14. public function testCanBuildTruck()
  15. {
  16. $truckBuilder = new TruckBuilder();
  17. $newVehicle = (new Director())->build($truckBuilder);
  18.  
  19. $this->assertInstanceOf(Truck::class, $newVehicle);
  20. }
  21.  
  22. public function testCanBuildCar()
  23. {
  24. $carBuilder = new CarBuilder();
  25. $newVehicle = (new Director())->build($carBuilder);
  26.  
  27. $this->assertInstanceOf(Car::class, $newVehicle);
  28. }
  29. }