在PHP项目开发过程中,我们经常会遇到需要创建包含大量属性的复杂对象的情况,比如一个电商订单对象,可能包含订单号、用户信息、商品列表、优惠信息、配送地址、支付状态等多个属性,部分属性还有默认值或者依赖关系。如果直接使用构造函数传入所有参数,调用时很容易搞混参数顺序,用大量setter方法逐个赋值又会让构建逻辑分散,后续修改构建流程时需要改动多处代码。建造者模式可以将对象的构建步骤拆分,让构建过程更灵活规范,下面我们就来看看PHP中如何实现这种模式。

建造者模式核心角色
建造者模式主要包含四个核心角色,每个角色的职责明确,共同完成复杂对象的构建:
- 产品类(Product):最终要构建的复杂对象,包含多个属性和对应的getter、setter方法。
- 抽象建造者(Builder):定义构建产品各个部分的抽象方法,以及返回最终产品的方法。
- 具体建造者(ConcreteBuilder):实现抽象建造者的方法,完成产品各个部分的具体构建,持有产品实例。
- 指挥者(Director):负责安排构建步骤的顺序,调用具体建造者的方法完成对象构建,隔离客户端和构建过程。
PHP实现建造者模式完整示例
我们以构建电商订单对象为例,演示完整的实现过程。
1. 定义产品类
产品类是最终要得到的复杂对象,这里定义订单的各个属性:
<?php
/**
* 订单产品类
*/
class Order
{
// 订单号
private string $orderNo;
// 用户ID
private int $userId;
// 商品列表
private array $goodsList = [];
// 优惠金额
private float $discountAmount = 0.00;
// 配送地址
private string $deliveryAddress = '';
// 订单状态
private string $status = '待支付';
// getter和setter方法
public function setOrderNo(string $orderNo): void
{
$this->orderNo = $orderNo;
}
public function getOrderNo(): string
{
return $this->orderNo;
}
public function setUserId(int $userId): void
{
$this->userId = $userId;
}
public function getUserId(): int
{
return $this->userId;
}
public function setGoodsList(array $goodsList): void
{
$this->goodsList = $goodsList;
}
public function getGoodsList(): array
{
return $this->goodsList;
}
public function setDiscountAmount(float $discountAmount): void
{
$this->discountAmount = $discountAmount;
}
public function getDiscountAmount(): float
{
return $this->discountAmount;
}
public function setDeliveryAddress(string $deliveryAddress): void
{
$this->deliveryAddress = $deliveryAddress;
}
public function getDeliveryAddress(): string
{
return $this->deliveryAddress;
}
public function setStatus(string $status): void
{
$this->status = $status;
}
public function getStatus(): string
{
return $this->status;
}
// 输出订单信息
public function printInfo(): void
{
echo "订单号:{$this->orderNo}" . PHP_EOL;
echo "用户ID:{$this->userId}" . PHP_EOL;
echo "商品列表:" . json_encode($this->goodsList, JSON_UNESCAPED_UNICODE) . PHP_EOL;
echo "优惠金额:{$this->discountAmount}" . PHP_EOL;
echo "配送地址:{$this->deliveryAddress}" . PHP_EOL;
echo "订单状态:{$this->status}" . PHP_EOL;
}
}
2. 定义抽象建造者
抽象建造者定义所有构建步骤的接口,以及返回最终产品的方法:
<?php
/**
* 抽象订单建造者
*/
interface OrderBuilder
{
// 构建订单号
public function buildOrderNo(): OrderBuilder;
// 构建用户信息
public function buildUserInfo(int $userId): OrderBuilder;
// 构建商品列表
public function buildGoodsList(array $goodsList): OrderBuilder;
// 构建优惠信息
public function buildDiscount(float $discountAmount): OrderBuilder;
// 构建配送地址
public function buildDeliveryAddress(string $address): OrderBuilder;
// 构建订单状态
public function buildStatus(string $status): OrderBuilder;
// 返回最终构建的订单对象
public function getOrder(): Order;
}
3. 定义具体建造者
具体建造者实现抽象建造者的方法,完成每个构建步骤的具体逻辑:
<?php
/**
* 具体订单建造者
*/
class ConcreteOrderBuilder implements OrderBuilder
{
// 持有订单产品实例
private Order $order;
public function __construct()
{
$this->order = new Order();
}
public function buildOrderNo(): OrderBuilder
{
// 这里可以生成默认订单号,也可以由外部传入,这里演示默认生成逻辑
$this->order->setOrderNo('ORD' . date('YmdHis') . rand(1000, 9999));
return $this;
}
public function buildUserInfo(int $userId): OrderBuilder
{
$this->order->setUserId($userId);
return $this;
}
public function buildGoodsList(array $goodsList): OrderBuilder
{
$this->order->setGoodsList($goodsList);
return $this;
}
public function buildDiscount(float $discountAmount): OrderBuilder
{
$this->order->setDiscountAmount($discountAmount);
return $this;
}
public function buildDeliveryAddress(string $address): OrderBuilder
{
$this->order->setDeliveryAddress($address);
return $this;
}
public function buildStatus(string $status): OrderBuilder
{
$this->order->setStatus($status);
return $this;
}
public function getOrder(): Order
{
return $this->order;
}
}
4. 定义指挥者
指挥者负责编排构建步骤,客户端只需要和指挥者交互,不需要关心具体构建细节:
<?php
/**
* 订单构建指挥者
*/
class OrderDirector
{
private OrderBuilder $builder;
public function __construct(OrderBuilder $builder)
{
$this->builder = $builder;
}
// 定义标准订单的构建流程
public function buildStandardOrder(int $userId, array $goodsList, string $address): Order
{
return $this->builder
->buildOrderNo()
->buildUserInfo($userId)
->buildGoodsList($goodsList)
->buildDeliveryAddress($address)
->getOrder();
}
// 定义优惠订单的构建流程
public function buildDiscountOrder(int $userId, array $goodsList, string $address, float $discount): Order
{
return $this->builder
->buildOrderNo()
->buildUserInfo($userId)
->buildGoodsList($goodsList)
->buildDiscount($discount)
->buildDeliveryAddress($address)
->getOrder();
}
}
5. 客户端调用示例
客户端只需要创建建造者和指挥者,调用对应的构建方法即可得到完整对象:
<?php
// 客户端调用
$builder = new ConcreteOrderBuilder();
$director = new OrderDirector($builder);
// 构建标准订单
$standardOrder = $director->buildStandardOrder(
1001,
[['id' => 1, 'name' => '手机', 'price' => 3999], ['id' => 2, 'name' => '耳机', 'price' => 399]],
'北京市朝阳区XX路XX号'
);
echo "标准订单信息:" . PHP_EOL;
$standardOrder->printInfo();
echo PHP_EOL;
// 构建优惠订单
$discountOrder = $director->buildDiscountOrder(
1002,
[['id' => 3, 'name' => '笔记本电脑', 'price' => 6999]],
'上海市浦东新区XX路XX号',
500.00
);
echo "优惠订单信息:" . PHP_EOL;
$discountOrder->printInfo();
建造者模式对比传统构建方式
我们可以通过一个简单表格对比两种方式的差异:
| 对比维度 | 传统构造函数/setter方式 | 建造者模式 |
|---|---|---|
| 参数管理 | 构造函数参数多时容易传混,setter方式步骤分散 | 构建步骤清晰,链式调用可读性强 |
| 构建流程控制 | 没有统一流程,客户端可以随意调整步骤顺序 | 指挥者统一控制流程,避免步骤遗漏 |
| 代码扩展性 | 新增构建步骤需要修改构造函数或者所有调用处 | 新增构建步骤只需要扩展建造者,不影响原有逻辑 |
| 复杂对象适配 | 适合属性少、构建简单的对象 | 适合属性多、构建过程有依赖的复杂对象 |
使用场景和注意事项
建造者模式适合以下场景:
- 对象包含多个属性,且部分属性有默认值或者依赖关系
- 对象的构建过程需要固定步骤,或者需要多种不同的构建流程
- 需要隔离复杂对象的创建和使用,让客户端不需要关心构建细节
使用时需要注意,如果对象本身很简单,属性很少,使用建造者模式会增加代码复杂度,反而得不偿失。另外,如果构建步骤经常变化,指挥者的逻辑也需要同步调整,这时候可以考虑让客户端直接调用建造者的方法,灵活编排步骤。