1.1. 建造者模式(Builder)

1.2.1. 目的

建造者是创建一个复杂对象的一部分接口。

有时候,如果建造者对他所创建的东西拥有较好的知识储备,这个接口就可能成为一个有默认方法的抽象类(又称为适配器)。

如果对象有复杂的继承树,那么对于建造者来说,有一个复杂继承树也是符合逻辑的。

注意:建造者通常有一个「流式接口」,例如 PHPUnit 模拟生成器。

1.2.2. 例子

  • PHPUnit: 模拟生成器

1.2.3. UML Diagram

1.2.4. 代码

你也可以在 GitHub 上找到这个代码。

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;

abstract class Vehicle
{
    /**
    * @var object[]
    */
    private $data = [];

    /**
    * @param string $key
    * @param object $value
    */
    public function setPart($key, $value)
    {
        $this->data[$key] = $value;
    }
}

Parts/Truck.php

<?php

namespace DesignPatterns\Creational\Builder\Parts;

class Truck extends Vehicle
{
}

Parts/Car.php

<?php

namespace DesignPatterns\Creational\Builder\Parts;

class Car extends Vehicle
{
}

Parts/Engine.php

<?php

namespace DesignPatterns\Creational\Builder\Parts;

class Engine
{
}

Parts/Wheel.php

<?php

namespace DesignPatterns\Creational\Builder\Parts;

class Wheel
{
}

Parts/Door.php

<?php

namespace DesignPatterns\Creational\Builder\Parts;

class Door
{
}

1.2.5. 测试

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);
    }
}
Image placeholder
周彪彪
未设置
  0人点赞

没有讨论,发表一下自己的看法吧

推荐文章
MVVM原理(Object.defineProperty和订阅者模式)

想着去了解vue的mvvm数据驱动是怎么实现的,百度中看了这篇文章,demo很好。其他文章只是讲到defineProperty的set,get。彻底理解Vue中的Watcher、Observer、De

清华大学教授马智亮:如何走向高度智慧建造?

什么是智慧建造?普遍意义上的智慧建造是指生物基于神经器官所具有的一种高级的综合能力,包括感知、知识、记忆、理解、联想、情感、逻辑、辨别、计算、分析、判断、文化等多种能力。显然,具备这种能力的生物,首当

1.0. 抽象工厂模式(Abstract Factory)

1.1.1.目的 在不指定具体类的情况下创建一系列相关或依赖对象。通常创建的类都实现相同的接口。抽象工厂的客户并不关心这些对象是如何创建的,它只是知道它们是如何一起运行的。 1.1.2.UML图 1

1.3. 工厂方法模式(Factory Method)

1.3.1.目的 对比简单工厂模式的优点是,您可以将其子类用不同的方法来创建一个对象。 举一个简单的例子,这个抽象类可能只是一个接口。 这种模式是「真正」的设计模式,因为他实现了S.O.L.I.D原则

关于 Python3 的编码(walker)

Python3中str与bytes的转换Thebytes/strdichotomyinPython3字符与Unicode编号之间的转换字符转Unicode编号>>>ord('A') 65 >>>hex

设计模式: 策略模式

博客主页定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。使用场景: 针对同一类型问题的多种处理方式,仅仅是具体行为有差别

Gradle Builds Everything —— Task 实例

上文讲述了Gradle中关于任务的基础概念,本文开始讲述下Task是如何定义的。为了方便,我们的语境分不开Gradle和AndroidGradlePlugin,因此此处不脱离Android环境来介绍G

集成 think-ORM 的 symfony bundle thinkorm-bundle

thinkorm-bundleSymfonyThinkOrmBundle关于thinkorm-bundle允许在你symfony使用thinkorm.所安装$composerrequireccwwwo

jquery children()与find()区别

jquerychildren()与find()区别1、find方法●返回匹配集合中每个元素的后代,参数selector是必须的,可以通过选择器对元素进行过滤,筛选出符合条件的元素。如果想选中所有的后代

jquery中children()和find()的区别是什么?

jquery中children()和find()的区别children(selector)方法是返回匹配元素集合中每个元素的所有子元素(仅儿子辈)。参数可选,添加参数表示通过选择器进行过滤,对元素进行

详解 PHP 中的三大经典模式

单例模式 单例模式的含义:作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统全局地提供这个实例。它不会创建实例副本,而是会向单例类内部存储的实例返回一个引用。单例模式的三

学习猿地开启IT在线课的精品模式

程序员的工作已经连续十年被国家评为“性价比”最高的职业,而这种技术岗位是需要有一定的技术功底才能从事的工作,需要长时间的、有目的学习积累,并且需要不断磨练,才可以胜任的工作。现在企业招聘程序员的要求越

学习猿地开创IT教育2.0模式

传统的学习方式都是进入班级,跟着老师面对面的学习。需要有几个硬性条件,就是在固定场地,并且在固定的时间里,按照老师安排的进度学习。基础不一样进度没办法调整、学习不好的跟不上会一直学习不好、有事旷课课程

详解 PHP 中的三大经典模式

单例模式 单例模式的含义:作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统全局地提供这个实例。它不会创建实例副本,而是会向单例类内部存储的实例返回一个引用。单例模式的三

Golang 里的 AES、DES、3DES 加解密,支持 ECB、CBC 等多种模式组合

Opensslencryption:OpenSSL库的功能包装,用于对称和非对称加密和解密。 AES-ECB AES-CBC DES-ECB DES-CBC 3DES-ECB 3DES-CBC 安

Go语言高级编程_1.6 常见的并发模式

1.6常见的并发模式 Go语言最吸引人的地方是它内建的并发支持。Go语言并发体系的理论是C.A.RHoare在1978年提出的CSP(CommunicatingSequentialProcess,通讯

在 Laravel 中实现「福勒的货币设计模式」

“这个世界上有很大比例的计算机都在操纵金钱,因此,我一直感到困惑的是,金钱实际上并不是任何主流编程语言中的一流数据类型。缺乏类型会导致问题,这是最明显的周边货币。如果您所有的计算都是用一种货币完成的

influxDB集群模式实践

influxDB数据库以其优秀的时序数据存储和查询能力,在处理和分析类似资源监控等时序数据方面得到了广泛的应用。而influxDB自带的各种特殊函数如求平均值、标准差、随机取数据,使数据分析变得十分方

老焦专栏 | 用 RACI 模式梳理业务流程,提高业务发布的效率

转载本文需注明出处:微信公众号EAWorld,违者必究。最近经常在不同场合说,技术发展已经进入深水区。IT技术发展已经越来越成熟了,尤其在金融行业,以前是解决从无到有的问题,现在该有的系统都有了,是解

职责驱动设计及状态模式的融会贯通

一、需求针对某通信产品,我们需要开发一个版本升级管理系统。该系统通过Java开发后台管理,由Telnet发起向前端基站设备的命令,以获取基站设备的版本信息,并在后台比较与当前最新版本的差异,以确定执行

适配器模式的三种形式

适配器模式,顾名思义,就是把原本不兼容的接口,通过适配,使之兼容。举个生活中简单的例子,以前的手机内存卡可以取出来,但是想和电脑之间传输音乐、视频等资料不能直接传输,需要通过USB读卡器,然后插入US

Python 面向对象 高阶-描述符与设计模式笔记

描述符 当一个类中,包含了三个魔术方法(__get__,__set__,__delete__)之一,或者全部时,那么这个类就称为描述符类 作用 描述符的作用就是对一个类中的某个成员进行一个详细的

Go编程语言教程_1.3. Golang的Hello World

你好,世界!是任何编程语言中的第一个基本程序。让我们使用以下步骤用Go语言编写第一个程序: 首先打开Go编译器。在Go语言中,该程序以.go扩展名保存,它是UTF-8文本文件。 现在,首先在程序中添加

gRPC-Go 和 Java 的一次 HelloWorld(十)

都说grpc是跨语言的一个rpc框架,当团队内部有多种流行编程语言时,那么grpc可以为他们提供通信,今天我们就通过一个HelloWorld来看看Java和Go是怎么通信的,一起实践吧,只有亲身实践才

Go语言高级编程_1.2 Hello, World 的革命

1.2Hello,World的革命 在创世纪章节中我们简单介绍了Go语言的演化基因族谱,对其中来自于贝尔实验室的特有并发编程基因做了重点介绍,最后引出了Go语言版的“Hello,World”程序。其实