一、什么是建造者模式
定义:建造者模式(Builder Pattern)又称生成器模式,是一种构建对象的模式。
1、它可以将一个产品的内部表象与产品的生成过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象。
2、由于建造零件的过程很复杂,因此,这些零件的建造过程往往被“外部化”到另一个乘坐建造者的对象里,建造者对象返还给客户端的是一个全部零件都建造完毕的产品对象。它将产品的结构和建造过程对客户端隐藏起来。
【释义】
使用生活中的例子来解释建造者模式:
例如:汽车生产,有不同厂家,不同种类的汽车。例如奔驰,宝马,奥迪又或者是卡车,轿车,SUV等。每种汽车的生产有相同之处,但又有区别。这个时候就可以利用到建造者思想模式嵌套进去。
二、建造者模式的四种角色
Product:表示被构造的复杂对象。ConcreateBuilder创建该产品的内部表示并定义它的装配过程。
Builder:抽象构造者类,为创建一个Product对象的各个部件指定抽象接口。
ConcreteBuilder:具体构造者类,实现Builder的接口以构造和装配该产品的各个部件。定义并明确它所创建的表示。提供一个检索产品的接口
Director:指挥者,构造一个使用Builder接口的对象。它主要是用于创建一个复杂的对象。它主要有两个作用:①是隔离了客户与对象的生产过程,②负责控制产品对象的生产过程。
三、建造者模式的使用场景
使用场景:一些基本的部件不会改变,而其它组合经常发生变化的时候。
四、建造者模式优缺点
优点
①每个具体构建者相互独立,利于系统扩展;
②客户端不必知道产品内部细节,利于细节风险控制;
③建造者模式比较独立,将对象本身与构建过程解耦
④精准控制构建出的对象和内容,构造层和显示层是分离的
缺点
①产品的组成部分必须相同,这限制了其使用范围。
②如果产品的内部变化复杂,该模式会增加很多的建造者类。
五、建造者模式与工厂模式的区别
①与抽象工厂模式相比,建造者模式返回一个组装好的完整产品,而抽象工厂模式返回一系列相关的产品,这些产品位于不同的产品等级结构,构成了一个产品族 。
②在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,而在建造者模式中,客户端可以不直接调用建造者的相关方法,而是通过指挥者类来指导如何生成对象,包括对象的组装过程和建造步骤,它侧重于一步步构造一个复杂对象,返回一个完整的对象 。
③如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车。
总结:建造者模式更关注于零件装配的顺序。
六、UML类图
七、示例代码
Director.php
<?php
namespace DesignPatterns\Creational\Builder;
use DesignPatterns\Creational\Builder\Parts\Vehicle;
/**
* Director 类是建造者模式的一部分。 它可以实现建造者模式的接口
* 并在构建器的帮助下构建一个复杂的对象
*
* 您也可以注入许多构建器而不是构建更复杂的对象
*/
class Director
{
public function build(BuilderInterface $builder): Vehicle
{
$builder->createVehicle();
$builder->addDoors();
$builder->addEngine();
$builder->addWheel();
return $builder->getVehicle();
}
}
BuilderInterface.php
<?php
namespace DesignPatterns\Creational\Builder;
use DesignPatterns\Creational\Builder\Parts\Vehicle;
interface BuilderInterface
{
public function createVehicle();
public function addWheel();
public function addEngine();
public function addDoors();
public function getVehicle(): Vehicle;
}
TruckBuilder.php
<?php
namespace DesignPatterns\Creational\Builder;
use DesignPatterns\Creational\Builder\Parts\Vehicle;
class TruckBuilder implements BuilderInterface
{
/**
* @var Parts\Truck
*/
private $truck;
public function addDoors()
{
$this->truck->setPart('rightDoor', new Parts\Door());
$this->truck->setPart('leftDoor', new Parts\Door());
}
public function addEngine()
{
$this->truck->setPart('truckEngine', new Parts\Engine());
}
public function addWheel()
{
$this->truck->setPart('wheel1', new Parts\Wheel());
$this->truck->setPart('wheel2', new Parts\Wheel());
$this->truck->setPart('wheel3', new Parts\Wheel());
$this->truck->setPart('wheel4', new Parts\Wheel());
$this->truck->setPart('wheel5', new Parts\Wheel());
$this->truck->setPart('wheel6', new Parts\Wheel());
}
public function createVehicle()
{
$this->truck = new Parts\Truck();
}
public function getVehicle(): Vehicle
{
return $this->truck;
}
}
CarBuilder.php
<?php
namespace DesignPatterns\Creational\Builder;
use DesignPatterns\Creational\Builder\Parts\Vehicle;
class CarBuilder implements BuilderInterface
{
/**
* @var Parts\Car
*/
private $car;
public function addDoors()
{
$this->car->setPart('rightDoor', new Parts\Door());
$this->car->setPart('leftDoor', new Parts\Door());
$this->car->setPart('trunkLid', new Parts\Door());
}
public function addEngine()
{
$this->car->setPart('engine', new Parts\Engine());
}
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());
}
public function createVehicle()
{
$this->car = new Parts\Car();
}
public function getVehicle(): Vehicle
{
return $this->car;
}
}
Parts/Vehicle.php
<?php
namespace DesignPatterns\Creational\Builder\Parts;
/**
* production vehicle Parts - Wheel
*/
class Wheel{}
/**
* production vehicle Parts - Engine
*/
class Engine{}
/**
* production vehicle Parts - Door
*/
class Door{}
abstract class Vehicle
{
/**
* @var object[]
*/
private $data = [];
/**
* @param string $key
* @param object $value
*/
public function setPart($key, $value)
{
$this->data[$key] = $value;
}
}
Parts/Car.php
<?php
namespace DesignPatterns\Creational\Builder\Parts;
class Car extends Vehicle
{
}
Parts/Truck.php
<?php
namespace DesignPatterns\Creational\Builder\Parts;
class Truck extends Vehicle
{
}
测试
Tests/DirectorTest.php
<?php
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);
}
}