2.2. Builder¶
2.2.1. Intent¶
According to the Gang of Four, the Builder pattern is a way to “separate the construction of a complex object from its representation so that the same construction process can create different representations” (Design Patterns: Elements of Reusable Object-Oriented Software, 2013, p. 97).
The construction process is controlled by a Director object and uses a step by step approach.
2.2.2. When to use it?¶
The Builder pattern should be used to create complex objects with lots of things to do to instantiate them. It permits to maintain creation algorithms decoupled from the rest of the code so that you can add objects’ representations without affecting the rest.
The Builder pattern focuses on creating complex objects in a step by step manner while the Abstract Factory pattern puts its emphasis on products’ families.
2.2.3. Diagram¶
Created using PhpStorm and yFiles.
2.2.4. Implementation¶
TrafficMap.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | <?php
namespace Phpatterns\Creational\Builder\TrafficMap;
/**
* Class TrafficMap
* A map used to emphasize traffic congestion.
*/
class TrafficMap
{
/** @var Point */
private $origin;
/** @var Point */
private $destination;
/** @var int */
private $height;
/** @var int */
private $width;
/** @var int */
private $waterColor;
/** @var int */
private $groundColor;
/** @var int */
private $lowTrafficColor;
/** @var int */
private $mediumTrafficColor;
/** @var int */
private $highTrafficColor;
/**
* @param Point $origin
* @param Point $destination
*/
public function __construct(Point $origin = null, Point $destination = null)
{
$this->origin = $origin;
$this->destination = $destination;
//default values
$this->height = 100;
$this->width = 100;
$this->waterColor = Color::CYAN;
$this->groundColor = Color::BROWN;
$this->lowTrafficColor = Color::YELLOW;
$this->mediumTrafficColor = Color::ORANGE;
$this->highTrafficColor = Color::RED;
}
/**
* @param Point $origin
* @return $this
*/
public function setOrigin(Point $origin)
{
$this->origin = $origin;
return $this;
}
/**
* @param Point $destination
* @return $this
*/
public function setDestination(Point $destination)
{
$this->destination = $destination;
return $this;
}
/**
* @param int $height
*/
public function setHeight($height)
{
$this->height = $height;
}
/**
* @param int $width
*/
public function setWidth($width)
{
$this->width = $width;
}
/**
* @param int $color
*/
public function setWaterColor($color)
{
$this->waterColor = $color;
}
/**
* @param int $color
*/
public function setGroundColor($color)
{
$this->groundColor = $color;
}
/**
* @param int $color
*/
public function setLowTrafficColor($color)
{
$this->lowTrafficColor = $color;
}
/**
* @param int $color
*/
public function setMediumTrafficColor($color)
{
$this->mediumTrafficColor = $color;
}
/**
* @param int $color
*/
public function setHighTrafficColor($color)
{
$this->highTrafficColor = $color;
}
}
|
Point.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | <?php
namespace Phpatterns\Creational\Builder\TrafficMap;
/**
* Class Point
* Represents a point in a Map
*/
class Point
{
/** @var float */
private $latitude;
/** @var float */
private $longitude;
/**
* @param float $latitude
* @param float $longitude
*/
public function __construct($latitude, $longitude)
{
$this->latitude = $latitude;
$this->longitude = $longitude;
}
/**
* @return float
*/
public function getLatitude()
{
return $this->latitude;
}
/**
* @return float
*/
public function getLongitude()
{
return $this->longitude;
}
}
|
Color.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php
namespace Phpatterns\Creational\Builder\TrafficMap;
class Color
{
const BLACK = 0x000000;
const BLUE = 0x0000FF;
const BROWN = 0x996633;
const CYAN = 0x00FFFF;
const DARK_GRAY = 0x444444;
const GRAY = 0x888888;
const GREEN = 0x00FF00;
const LIGHT_GRAY = 0xCCCCCC;
const MAGENTA = 0xFF00FF;
const ORANGE = 0xFF6600;
const RED = 0xFF0000;
const WHITE = 0xFFFFFF;
const YELLOW = 0xFFFF00;
}
|
TrafficMapBuilderInterface.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | <?php
namespace Phpatterns\Creational\Builder;
interface TrafficMapBuilderInterface
{
/**
* @return TrafficMap\TrafficMap
*/
public function getMap();
/**
* @return $this
*/
public function setOrigin();
/**
* @return $this
*/
public function setDestination();
/**
* @return $this
*/
public function setHeight();
/**
* @return $this
*/
public function setWidth();
/**
* @return $this
*/
public function setWaterColor();
/**
* @return $this
*/
public function setGroundColor();
/**
* @return $this
*/
public function setLowTrafficColor();
/**
* @return $this
*/
public function setMediumTrafficColor();
/**
* @return $this
*/
public function setHighTrafficColor();
}
|
ParisToBerlinTrafficMapBuilder.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | <?php
namespace Phpatterns\Creational\Builder\ConcreteBuilder;
use Phpatterns\Creational\Builder;
use Phpatterns\Creational\Builder\TrafficMap;
class ParisToBerlinTrafficMapBuilder implements Builder\TrafficMapBuilderInterface
{
/** @var TrafficMap\TrafficMap */
protected $map;
public function __construct()
{
$this->map = new TrafficMap\TrafficMap();
}
/**
* @return TrafficMap\TrafficMap
*/
public function getMap()
{
return $this->map;
}
/**
* @return $this
*/
public function setOrigin()
{
$this->map->setOrigin(
new TrafficMap\Point(48.856614, 2.3522219000000177) // Paris
);
return $this;
}
/**
* @return $this
*/
public function setDestination()
{
$this->map->setOrigin(
new TrafficMap\Point(52.52000659999999, 13.404953999999975) // Berlin
);
return $this;
}
/**
* @return $this
*/
public function setHeight()
{
$this->map->setHeight(100);
return $this;
}
/**
* @return $this
*/
public function setWidth()
{
$this->map->setWidth(200);
return $this;
}
/**
* @return $this
*/
public function setWaterColor()
{
$this->map->setWaterColor(TrafficMap\Color::BLUE);
return $this;
}
/**
* @return $this
*/
public function setGroundColor()
{
$this->map->setGroundColor(TrafficMap\Color::DARK_GRAY);
return $this;
}
/**
* @return $this
*/
public function setLowTrafficColor()
{
$this->map->setLowTrafficColor(TrafficMap\Color::LIGHT_GRAY);
return $this;
}
/**
* @return $this
*/
public function setMediumTrafficColor()
{
$this->map->setMediumTrafficColor(TrafficMap\Color::MAGENTA);
return $this;
}
/**
* @return $this
*/
public function setHighTrafficColor()
{
$this->map->setHighTrafficColor(TrafficMap\Color::ORANGE);
return $this;
}
}
|
SanFranciscoToSantaCruzTrafficMapBuilder.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | <?php
namespace Phpatterns\Creational\Builder\ConcreteBuilder;
use Phpatterns\Creational\Builder;
use Phpatterns\Creational\Builder\TrafficMap;
class SanFranciscoToSantaCruzTrafficMapBuilder implements Builder\TrafficMapBuilderInterface
{
/** @var TrafficMap\TrafficMap */
protected $map;
public function __construct()
{
$this->map = new TrafficMap\TrafficMap();
}
/**
* @return TrafficMap\TrafficMap
*/
public function getMap()
{
return $this->map;
}
/**
* @return $this
*/
public function setOrigin()
{
$this->map->setOrigin(
new TrafficMap\Point(37.7749295, -122.41941550000001) // San Francisco
);
return $this;
}
/**
* @return $this
*/
public function setDestination()
{
$this->map->setOrigin(
new TrafficMap\Point(36.9741171, -122.03079630000002) // Santa Cruz
);
return $this;
}
/**
* @return $this
*/
public function setHeight()
{
$this->map->setHeight(250);
return $this;
}
/**
* @return $this
*/
public function setWidth()
{
$this->map->setWidth(150);
return $this;
}
/**
* @return $this
*/
public function setWaterColor()
{
$this->map->setWaterColor(TrafficMap\Color::CYAN);
return $this;
}
/**
* @return $this
*/
public function setGroundColor()
{
$this->map->setGroundColor(TrafficMap\Color::BLACK);
return $this;
}
/**
* @return $this
*/
public function setLowTrafficColor()
{
//don't do anything and keep the default value from TrafficMap\TrafficMap's constructor
return $this;
}
/**
* @return $this
*/
public function setMediumTrafficColor()
{
//don't do anything and keep the default value from TrafficMap\TrafficMap's constructor
return $this;
}
/**
* @return $this
*/
public function setHighTrafficColor()
{
//don't do anything and keep the default value from TrafficMap\TrafficMap's constructor
return $this;
}
}
|
TrafficMapDirector.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <?php
namespace Phpatterns\Creational\Builder;
use Phpatterns\Creational\Builder\TrafficMap;
class TrafficMapDirector
{
/**
* The director constructs a TrafficMap using the TrafficMapBuilderInterface
* (he knows nothing about the concrete details of the creation)
* @param TrafficMapBuilderInterface $builder
* @return TrafficMap\TrafficMap
*/
public function buildMap(TrafficMapBuilderInterface $builder)
{
return $builder
->setOrigin()
->setDestination()
->setHeight()
->setWidth()
->setWaterColor()
->setGroundColor()
->setLowTrafficColor()
->setMediumTrafficColor()
->setHighTrafficColor()
->getMap();
}
}
|
2.2.5. Tests¶
TrafficMapDirectorTest.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | <?php
namespace Test\Phpatterns\Creational\Builder;
use Phpatterns\Creational\Builder;
use Phpatterns\Creational\Builder\ConcreteBuilder;
use Phpatterns\Creational\Builder\TrafficMap;
class TrafficMapDirectorTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Builder\TrafficMapDirector
*/
private $trafficMapDirector;
protected function setUp()
{
$this->trafficMapDirector = new Builder\TrafficMapDirector();
}
/**
* Testing if concrete builders implement TrafficMapBuilderInterface
* @param Builder\TrafficMapBuilderInterface $builder
* @dataProvider buildersProvider
*/
public function testConcreteBuildersImplementBuilderInterface(Builder\TrafficMapBuilderInterface $builder)
{
$this->assertInstanceOf(Builder\TrafficMapBuilderInterface::class, $builder);
}
/**
* Testing creation mechanism
* @param Builder\TrafficMapBuilderInterface $builder
* @dataProvider buildersProvider
*/
public function testCreationMechanism(Builder\TrafficMapBuilderInterface $builder)
{
$this->assertInstanceOf(
TrafficMap\TrafficMap::class,
$this->trafficMapDirector->buildMap($builder)
);
}
public function buildersProvider()
{
return [
[new ConcreteBuilder\ParisToBerlinTrafficMapBuilder()],
[new ConcreteBuilder\SanFranciscoToSantaCruzTrafficMapBuilder()]
];
}
}
|