建造者模式(Builder)
1、模式定义
建造者模式将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
2、问题引出
假设我们有个生产车的工厂,可以制造各种车,比如自行车、汽车、卡车等等,如果每辆车都是从头到尾按部就班地造,必然效率低下。
3、解决办法
我们可以试着将车的组装和零部件生产分离开来:让一个类似“导演”的角色负责车子组装,而具体造什么样的车需要什么样的零部件让具体的“构造者”去实现,“导演”知道什么样的车怎么造,需要的零部件则让“构造者”去建造,何时完成由“导演”来控制并最终返回给客户端。
4、UML类图
5、示例代码
Director.php
<?php
namespace DesignPatterns\Creational\Builder;
/**
* Director 是建造者模式的一部分,它知道建造者接口并通过建造者构建复杂对象。
*
* 可以通过依赖注入建造者的方式构造任何复杂对象
*/
class Director
{
/**
* “导演”并不知道具体实现细节
*
* @param BuilderInterface $builder
*
* @return Parts\Vehicle
*/
public function build(BuilderInterface $builder)
{
$builder->createVehicle();
$builder->addDoors();
$builder->addEngine();
$builder->addWheel();
return $builder->getVehicle();
}
}
BuilderInterface.php
<?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
<?php
namespace DesignPatterns\Creational\Builder;
/**
* BikeBuilder用于建造自行车
*/
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
<?php
namespace DesignPatterns\Creational\Builder;
/**
* CarBuilder用于建造汽车
*/
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
<?php
namespace DesignPatterns\Creational\Builder\Parts;
/**
* VehicleInterface是车辆接口
*/
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
<?php
namespace DesignPatterns\Creational\Builder\Parts;
/**
* Bike
*/
class Bike extends Vehicle
{
}
Parts/Car.php
<?php
namespace DesignPatterns\Creational\Builder\Parts;
/**
* Car
*/
class Car extends Vehicle
{
}
Parts/Engine.php
<?php
namespace DesignPatterns\Creational\Builder\Parts;
/**
* Engine类
*/
class Engine
{
}
Parts/Wheel.php
<?php
namespace DesignPatterns\Creational\Builder\Parts;
/**
* Wheel类
*/
class Wheel
{
}
Parts/Door.php
<?php
namespace DesignPatterns\Creational\Builder\Parts;
/**
* Door类
*/
class Door
{
}
6、测试代码
Tests/DirectorTest.php
<?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 用于测试建造者模式
*/
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())
);
}
/**
* 这里我们测试建造过程,客户端并不知道具体的建造者。
*
* @dataProvider getBuilder
*/
public function testBuild(BuilderInterface $builder)
{
$newVehicle = $this->director->build($builder);
$this->assertInstanceOf('DesignPatterns\Creational\Builder\Parts\Vehicle', $newVehicle);
}
}
7、总结
建造者模式和抽象工厂模式很像,总体上,建造者模式仅仅只比抽象工厂模式多了一个“导演类”的角色。与抽象工厂模式相比,建造者模式一般用来创建更为复杂的对象,因为对象的创建过程更为复杂,因此将对象的创建过程独立出来组成一个新的类 —— 导演类。也就是说,抽像工厂模式是将对象的全部创建过程封装在工厂类中,由工厂类向客户端提供最终的产品;而建造者模式中,建造者类一般只提供产品类中各个组件的建造,而将完整建造过程交付给导演类。由导演类负责将各个组件按照特定的规则组建为产品,然后将组建好的产品交付给客户端。
8 Comments
我连PHPUnit都不懂,哎
\PHPUnit_Framework_TestCase现在好像调用不通了,改成Tests\TestCase就可以了。