1.2. Budowniczy (Builder)¶
1.2.1. Przeznaczenie¶
Wzorzec Budowniczego pozwala na podział skomplikowanego procesu tworzenia obiektu, na kilka mniejszych etapów, gdzie każdy z nich może być implementowany na różne sposoby. Budowniczy jest interfejsem, który pozwala budować części takiego obiektu.
Jeżeli Budowniczy ma najlepszą wiedzę na temat tworzonego obiektu, wtedy zamiast interfejsu można zastosować klasę abstrakcyjną z domyślnymi metodami (patrz Adapter).
Jeżeli struktura dziedziczenia poszczególnych klas jest rozbudowana, wtedy struktura dziedziczenia Budowniczych powinna temu odpowiadać.
Budowniczy często wykorzystuje płynny interfejs (ang. fluent interface) jak na przykład Mock Builder z biblioteki PHPUnit.
1.2.2. Przykłady¶
- PHPUnit: Mock Builder
1.2.3. Diagram UML¶

1.2.4. Kod¶
Ten kod znajdziesz również na GitHub.
Director.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 | <?php
declare(strict_types=1);
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(Builder $builder): Vehicle
{
$builder->createVehicle();
$builder->addDoors();
$builder->addEngine();
$builder->addWheel();
return $builder->getVehicle();
}
}
|
Builder.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php
declare(strict_types=1);
namespace DesignPatterns\Creational\Builder;
use DesignPatterns\Creational\Builder\Parts\Vehicle;
interface Builder
{
public function createVehicle();
public function addWheel();
public function addEngine();
public function addDoors();
public function getVehicle(): Vehicle;
}
|
TruckBuilder.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 | <?php
declare(strict_types=1);
namespace DesignPatterns\Creational\Builder;
use DesignPatterns\Creational\Builder\Parts\Door;
use DesignPatterns\Creational\Builder\Parts\Engine;
use DesignPatterns\Creational\Builder\Parts\Wheel;
use DesignPatterns\Creational\Builder\Parts\Truck;
use DesignPatterns\Creational\Builder\Parts\Vehicle;
class TruckBuilder implements Builder
{
private Truck $truck;
public function addDoors()
{
$this->truck->setPart('rightDoor', new Door());
$this->truck->setPart('leftDoor', new Door());
}
public function addEngine()
{
$this->truck->setPart('truckEngine', new Engine());
}
public function addWheel()
{
$this->truck->setPart('wheel1', new Wheel());
$this->truck->setPart('wheel2', new Wheel());
$this->truck->setPart('wheel3', new Wheel());
$this->truck->setPart('wheel4', new Wheel());
$this->truck->setPart('wheel5', new Wheel());
$this->truck->setPart('wheel6', new Wheel());
}
public function createVehicle()
{
$this->truck = new Truck();
}
public function getVehicle(): Vehicle
{
return $this->truck;
}
}
|
CarBuilder.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 | <?php
declare(strict_types=1);
namespace DesignPatterns\Creational\Builder;
use DesignPatterns\Creational\Builder\Parts\Door;
use DesignPatterns\Creational\Builder\Parts\Engine;
use DesignPatterns\Creational\Builder\Parts\Wheel;
use DesignPatterns\Creational\Builder\Parts\Car;
use DesignPatterns\Creational\Builder\Parts\Vehicle;
class CarBuilder implements Builder
{
private Car $car;
public function addDoors()
{
$this->car->setPart('rightDoor', new Door());
$this->car->setPart('leftDoor', new Door());
$this->car->setPart('trunkLid', new Door());
}
public function addEngine()
{
$this->car->setPart('engine', new Engine());
}
public function addWheel()
{
$this->car->setPart('wheelLF', new Wheel());
$this->car->setPart('wheelRF', new Wheel());
$this->car->setPart('wheelLR', new Wheel());
$this->car->setPart('wheelRR', new Wheel());
}
public function createVehicle()
{
$this->car = new Car();
}
public function getVehicle(): Vehicle
{
return $this->car;
}
}
|
Parts/Vehicle.php
1 2 3 4 5 6 7 8 9 10 11 12 | <?php
declare(strict_types=1);
namespace DesignPatterns\Creational\Builder\Parts;
abstract class Vehicle
{
public function setPart(string $key, object $value)
{
}
}
|
Parts/Truck.php
1 2 3 4 5 6 7 8 9 | <?php
declare(strict_types=1);
namespace DesignPatterns\Creational\Builder\Parts;
class Truck extends Vehicle
{
}
|
Parts/Car.php
1 2 3 4 5 6 7 8 9 | <?php
declare(strict_types=1);
namespace DesignPatterns\Creational\Builder\Parts;
class Car extends Vehicle
{
}
|
Parts/Engine.php
1 2 3 4 5 6 7 8 9 | <?php
declare(strict_types=1);
namespace DesignPatterns\Creational\Builder\Parts;
class Engine
{
}
|
Parts/Wheel.php
1 2 3 4 5 6 7 8 9 | <?php
declare(strict_types=1);
namespace DesignPatterns\Creational\Builder\Parts;
class Wheel
{
}
|
Parts/Door.php
1 2 3 4 5 6 7 8 9 | <?php
declare(strict_types=1);
namespace DesignPatterns\Creational\Builder\Parts;
class Door
{
}
|
1.2.5. Testy¶
Tests/DirectorTest.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 | <?php
declare(strict_types=1);
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);
}
}
|