1.2. 빌더 (Builder)¶
1.2.1. 사용 목적¶
빌더는 복잡한 객체의 일부를 생성하는 인터페이스 입니다.
때때로, 빌더는 그것에 대해 더 명확한 정보(Knowledge)를 가질 때, 해당 인터페이스는 기본 매서드(일명 Adapter)를 가진 추상클래스가 됩니다.
만약 객체들에 복잡한 상속 트리가 있는 경우에, 빌더 또한 복잡한 상속 트리를 가져야 마땅합니다.
Note: 빌더들은 보통 유연한 인터페이스를 가지는데, PHPUnit의 mock builder가 그 예 입니다.
1.2.2. 예시¶
- PHPUnit: Mock Builder
1.2.3. UML 다이어그램¶
1.2.4. 코드¶
코드는 또한 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 27 28 29 30 | <?php
namespace DesignPatterns\Creational\Builder;
/**
* 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
{
/**
* The director don't know about concrete part
*
* @param BuilderInterface $builder
*
* @return Parts\Vehicle
*/
public function build(BuilderInterface $builder)
{
$builder->createVehicle();
$builder->addDoors();
$builder->addEngine();
$builder->addWheel();
return $builder->getVehicle();
}
}
|
BuilderInterface.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 | <?php
namespace DesignPatterns\Creational\Builder;
/**
*
*/
interface BuilderInterface
{
/**
* @return mixed
*/
public function createVehicle();
/**
* @return mixed
*/
public function addWheel();
/**
* @return mixed
*/
public function addEngine();
/**
* @return mixed
*/
public function addDoors();
/**
* @return mixed
*/
public function getVehicle();
}
|
BikeBuilder.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 | <?php
namespace DesignPatterns\Creational\Builder;
/**
* BikeBuilder builds bike
*/
class BikeBuilder implements BuilderInterface
{
/**
* @var Parts\Bike
*/
protected $bike;
/**
* {@inheritdoc}
*/
public function addDoors()
{
}
/**
* {@inheritdoc}
*/
public function addEngine()
{
$this->bike->setPart('engine', new Parts\Engine());
}
/**
* {@inheritdoc}
*/
public function addWheel()
{
$this->bike->setPart('forwardWheel', new Parts\Wheel());
$this->bike->setPart('rearWheel', new Parts\Wheel());
}
/**
* {@inheritdoc}
*/
public function createVehicle()
{
$this->bike = new Parts\Bike();
}
/**
* {@inheritdoc}
*/
public function getVehicle()
{
return $this->bike;
}
}
|
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 47 48 49 50 51 52 53 54 55 56 57 58 | <?php
namespace DesignPatterns\Creational\Builder;
/**
* CarBuilder builds car
*/
class CarBuilder implements BuilderInterface
{
/**
* @var Parts\Car
*/
protected $car;
/**
* @return void
*/
public function addDoors()
{
$this->car->setPart('rightdoor', new Parts\Door());
$this->car->setPart('leftDoor', new Parts\Door());
}
/**
* @return void
*/
public function addEngine()
{
$this->car->setPart('engine', new Parts\Engine());
}
/**
* @return void
*/
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());
}
/**
* @return void
*/
public function createVehicle()
{
$this->car = new Parts\Car();
}
/**
* @return Parts\Car
*/
public function getVehicle()
{
return $this->car;
}
}
|
Parts/Vehicle.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <?php
namespace DesignPatterns\Creational\Builder\Parts;
/**
* VehicleInterface is a contract for a vehicle
*/
abstract class Vehicle
{
/**
* @var array
*/
protected $data;
/**
* @param string $key
* @param mixed $value
*/
public function setPart($key, $value)
{
$this->data[$key] = $value;
}
}
|
Parts/Bike.php
1 2 3 4 5 6 7 8 9 10 | <?php
namespace DesignPatterns\Creational\Builder\Parts;
/**
* Bike is a bike
*/
class Bike extends Vehicle
{
}
|
Parts/Car.php
1 2 3 4 5 6 7 8 9 10 | <?php
namespace DesignPatterns\Creational\Builder\Parts;
/**
* Car is a car
*/
class Car extends Vehicle
{
}
|
Parts/Engine.php
1 2 3 4 5 6 7 8 9 10 | <?php
namespace DesignPatterns\Creational\Builder\Parts;
/**
* Class Engine
*/
class Engine
{
}
|
Parts/Wheel.php
1 2 3 4 5 6 7 8 9 10 | <?php
namespace DesignPatterns\Creational\Builder\Parts;
/**
* Class Wheel
*/
class Wheel
{
}
|
Parts/Door.php
1 2 3 4 5 6 7 8 9 10 | <?php
namespace DesignPatterns\Creational\Builder\Parts;
/**
* Class Door
*/
class Door
{
}
|
1.2.5. 테스트¶
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 32 33 34 35 36 37 38 39 40 41 42 | <?php
namespace DesignPatterns\Creational\Builder\Tests;
use DesignPatterns\Creational\Builder\Director;
use DesignPatterns\Creational\Builder\CarBuilder;
use DesignPatterns\Creational\Builder\BikeBuilder;
use DesignPatterns\Creational\Builder\BuilderInterface;
/**
* DirectorTest tests the builder pattern
*/
class DirectorTest extends \PHPUnit_Framework_TestCase
{
protected $director;
protected function setUp()
{
$this->director = new Director();
}
public function getBuilder()
{
return array(
array(new CarBuilder()),
array(new BikeBuilder())
);
}
/**
* Here we test the build process. Notice that the client don't know
* anything about the concrete builder.
*
* @dataProvider getBuilder
*/
public function testBuild(BuilderInterface $builder)
{
$newVehicle = $this->director->build($builder);
$this->assertInstanceOf('DesignPatterns\Creational\Builder\Parts\Vehicle', $newVehicle);
}
}
|