PHP 生成器模式
目的
生成器模式(Builder,或称建造者模式)是一个接口,用于构建复杂对象的各个部分。
在某些情况下,如果生成器对其构建的内容有很好的了解,那么这个接口可以是一个抽象类,并会有一个默认方法(也称适配器)。
如果对象具有复杂的继承结构,那么按照的正常逻辑,生成器也应该有一个复杂的继承结构。
注意:生成器通常有都有一个完善的接口,例如 PHPUnit 的模拟生成器(Mock Builder)。
例子
- PHPUnit: 模拟生成器(Mock Builder)
UML 图
代码
Director.php
<?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
<?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
<?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
<?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
<?php
declare(strict_types=1);
namespace DesignPatterns\Creational\Builder\Parts;
abstract class Vehicle{
public function setPart(string $key, object $value){}
}
Parts/Truck.php
<?php
declare(strict_types=1);
namespace DesignPatterns\Creational\Builder\Parts;
class Truck extends Vehicle{}
Parts/Car.php
<?php
declare(strict_types=1);
namespace DesignPatterns\Creational\Builder\Parts;
class Car extends Vehicle{}
Parts/Engine.php
<?php
declare(strict_types=1);
namespace DesignPatterns\Creational\Builder\Parts;
class Engine{}
Parts/Wheel.php
<?php
declare(strict_types=1);
namespace DesignPatterns\Creational\Builder\Parts;
class Wheel{}
Parts/Door.php
<?php
declare(strict_types=1);
namespace DesignPatterns\Creational\Builder\Parts;
class Door{}
测试
Tests/DirectorTest.php
<?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);
}
}