PHP设计模式之建造者模式(Builder Pattern)

建造者模式(Builder Pattern)是一种创建型设计模式,它将产品创建的复杂过程分解,使得同样的创建过程能构建不同的产品。通过汽车生产实例解释,建造者模式包括Product(汽车)、Builder(汽车构造接口)、ConcreteBuilder(具体汽车建造者如奔驰、宝马建造者)和Director(指挥者)四个角色。这种模式适用于组件不变但组合变化的情况,优点在于解耦构造过程,易于扩展。然而,它也要求所有产品具有相同的组成部分,并可能导致大量建造者类。建造者模式与工厂模式的主要区别在于,前者关注于构建过程的顺序,后者则返回一系列相关产品。提供的代码示例展示了如何使用PHP实现建造者模式。

一、什么是建造者模式                

定义:建造者模式(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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值