PHP设计模式之建造者模式(Builder)原理与用法案例详解


Posted in PHP onDecember 12, 2019

本文实例讲述了PHP设计模式之建造者模式(Builder)原理与用法。分享给大家供大家参考,具体如下:

这个建造者模式,我们也可以称为生成器模式,核心思想是将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式,简单点来说就是为了消除其它对象复杂的创建过程。

例如:汽车,他的发动机引擎有好多品牌,轮胎也有各种材质,内饰更是千奇百怪;鸟,他的头、翅膀以及脚有各种颜色和形状,在创建这种复杂对象的时候,我们建议使用建造者模式。

先来看一个案例来感受下什么是建造者模式:

  1. 有一个用户的UserInfo类,创建这个类,需要创建用户的姓名,年龄,金钱等信息,才能获得用户具体的信息结果。
  2. 创建一个UserInfoBuilder 用户建造者类,这个类,将UserInfo复杂的创建姓名,年龄,金钱等操作封装起来,简化用户类的创建过程

完事代码如下:

//建造者模式,目的是消除其它对象复杂的创建过程
/* 描述一个用户的类,包含用户姓名,年龄,金钱 */
class UserInfo {
    protected $userName = ''; 
    protected $userAge = '';
    protected $userMoney = '';
    public function setUserName($userName) {
        $this->userName = $userName;
    }
    public function setUserAge($userAge) {
        $this->userAge = $userAge;
    }
    public function setUserMoney($userMoney) {
        $this->userMoney = $userMoney;
    }
    public function getPeople() {
        echo "这个人的姓名是:" . $this->setUserName . ',年龄是:' . $this->userAge . ', 金钱:' . $this->userMoney;
    }
}
/* 实例化,并且创建这个用户的时候,是很痛苦的,需要设置用户名,年龄和金钱*/
$peopleInfo = array(
    'userName' => 'initphp',
    'userAge' => 28,
    'userMoney' => '100元'
    );
$UserInfo = new UserInfo;
//下面需要一步步的设置用户信息,才能得到用户详细信息,过程纠结而痛苦
$UserInfo->setUserName($peopleInfo['userName']); 
$UserInfo->setUserAge($peopleInfo['userAge']);
$UserInfo->setUserMoney($peopleInfo['userMoney']);
$UserInfo->getPeople();
//UserInfoBuilder 用户信息建造者类,将UserInfo的创建过程封装掉,开发者使用起来心情舒畅
<?php
//建造者模式,目的是消除其它对象复杂的创建过程
include("UserInfo.php");
class UserInfoBuilder {
    protected $obj;
    public function __construct() {
        $this->obj = new UserInfo;
    }
    public function buildPeople($peopleInfo) {
        $this->obj->setUserName($peopleInfo['userName']);
        $this->obj->setUserAge($peopleInfo['userAge']);
        $this->obj->setUserMoney($peopleInfo['userMoney']);
    } 
    public function getPeople() {
        $this->obj->getPeople();
    }
}
/* 创建过程被封装了,用户使用简单了 */
$peopleInfo = array(
    'userName' => 'initphp',
    'userAge' => 28,
    'userMoney' => '100元'
    );
$UserInfoBuilder = new UserInfoBuilder;
$UserInfoBuilder->buildPeople($peopleInfo); //直接一个build
$UserInfoBuilder->getPeople();

大概了解了之后,咱们就来继续看。

一般情况下,建造者模式一般有以下四种角色:

     1.产品角色,产品角色定义自身的组成属性

     2.抽象建造者,抽象建造者定义了产品的创建过程以及如何返回一个产品

     3.具体建造者,具体建造者实现了抽象建造者创建产品过程的方法,给产品的具体属性进行赋值定义

     4.指挥者,指挥者负责与调用客户端交互,决定创建什么样的产品

这四个角色也可以按照如下方式来理解:

  1. 抽象建造者(Builder)角色:定义一个抽象接口,规范产品各个组成成分的建造(即规范具体建造者的方法实现)。其中所规范的方法中必须包括建造方法和结果返回方法
  2. 具体建造者(ConcreteBuilder)角色:实现抽象建造者角色所定义的方法。具体建造者与业务逻辑关联性较大,应用程序最终会通过调用此角色中所实现的建造方法按照业务逻辑创建产品,在建造完成后通过结果返回方法返回建造的产品实例。一般在外部由客户或一个抽象工厂创建。
  3. 导演者(Director)角色:此角色的作用是调用具体的建造者角色建造产品。导演者与产品类没有直接关系,与产品类交谈的是具体抽象角色。
  4. 产品(Product)角色:在指导者的指导下由建造者所创建的那个复杂的对象导演者角色与客户端直接打交道,它理解客户端的业务逻辑,将客户端创建产品的请求拆分成对产品组成部分的请求,然后调用具体产品角色执行建造操作。它分离了客户端与具体建造者。

再来看个实例:

<?php
/**
 * Created by PhpStorm.
 * User: Jiang
 * Date: 2015/4/25
 * Time: 9:31
 */
/**具体产品角色 鸟类
 * Class Bird
 */
class Bird
{
  public $_head;
  public $_wing;
  public $_foot;
  function show()
  {
    echo "头的颜色:{$this->_head}<br/>";
    echo "翅膀的颜色:{$this->_wing}<br/>";
    echo "脚的颜色:{$this->_foot}<br/>";
  }
}
/**抽象鸟的建造者(生成器)
 * Class BirdBuilder
 */
abstract class BirdBuilder
{
  protected $_bird;
  function __construct()
  {
    $this->_bird=new Bird();
  }
  abstract function BuildHead();
  abstract function BuildWing();
  abstract function BuildFoot();
  abstract function GetBird();
}
/**具体鸟的建造者(生成器)  蓝鸟
 * Class BlueBird
 */
class BlueBird extends BirdBuilder
{
  function BuildHead()
  {
    // TODO: Implement BuilderHead() method.
    $this->_bird->_head="Blue";
  }
  function BuildWing()
  {
    // TODO: Implement BuilderWing() method.
    $this->_bird->_wing="Blue";
  }
  function BuildFoot()
  {
    // TODO: Implement BuilderFoot() method.
    $this->_bird->_foot="Blue";
  }
  function GetBird()
  {
    // TODO: Implement GetBird() method.
    return $this->_bird;
  }
}
/**玫瑰鸟
 * Class RoseBird
 */
class RoseBird extends BirdBuilder
{
  function BuildHead()
  {
    // TODO: Implement BuildHead() method.
    $this->_bird->_head="Red";
  }
  function BuildWing()
  {
    // TODO: Implement BuildWing() method.
    $this->_bird->_wing="Black";
  }
  function BuildFoot()
  {
    // TODO: Implement BuildFoot() method.
    $this->_bird->_foot="Green";
  }
  function GetBird()
  {
    // TODO: Implement GetBird() method.
    return $this->_bird;
  }
}
/**指挥者
 * Class Director
 */
class Director
{
  /**
   * @param $_builder   建造者
   * @return mixed     产品类:鸟
   */
  function Construct($_builder)
  {
    $_builder->BuildHead();
    $_builder->BuildWing();
    $_builder->BuildFoot();
    return $_builder->GetBird();
  }
}
//调用代码
header("Content-Type:text/html;charset=utf-8");
//------------------------生成器模式测试代码------------------
require_once "./Builder/Builder.php";
$director=new Director();
echo "蓝鸟的组成:<hr/>";
$blue_bird=$director->Construct(new BlueBird());
$blue_bird->Show();
echo "<br/>Rose鸟的组成:<hr/>";
$rose_bird=$director->Construct(new RoseBird());
$rose_bird->Show();

建造者模式它的优点很明显,就是它可以很好的将一个对象的实现与相关的“业务”逻辑分离开来,从而可以在不改变事件逻辑的前提下,使增加(或改变)实现变得非常容易,缺点也是同样,那就是建造者接口的修改会导致所有执行类的修改。

关于这个建造者模式,它还有以下三个扩展模式:

  1. 抽象工厂模式(abstract factory模式):在抽象工厂模式中,每一次工厂对象被调用时都会返还一个完整的产品对象,而客户端可能会将这些产品组装成一个更大更复杂的产品,也可能不会。建造者模式则不同,它一点一点地建造出一个复杂的产品,而这个产品的组装过程发生在建造者内部。二者的区别在于是否有组装过程,组装过程发生的位置。这两个设计模式可以连起来用,客户端通过调用一个建造角色,间接调用另一个抽象工厂模式的工厂角色。工厂模式返还不同产品族的零件,而建造者模式则把它们组装起来。
  2. 策略模式(strategy模式):建造者模式在结构上很接近于策略模式,事实上建造者模式是策略模式的一种特殊情况。二者的区别在于用意不同。建造者模式作用于客户端一点一点的建造新的对象,而策略模式的目的是为算法提供抽象的接口。
  3. 建造者模式与模板方法模式:建造者模式在退化、失去导演者角色后,可以发展到模板方法模式(即将建造过程的算法实现放在建造角色中)。

以下情况应当使用建造者模式:

   1、 需要生成的产品对象有复杂的内部结构。
   2、 需要生成的产品对象的属性相互依赖,建造者模式可以强迫生成顺序。
   3、 在对象创建过程中会使用到系统中的一些其它对象,这些对象在产品对象的创建过程中不易得到。

使用建造者模式主要有以下效果:

   1、 建造者模式的使用使得产品的内部表象可以独立的变化。使用建造者模式可以使客户端不必知道产品内部组成的细节。
   2、 每一个Builder都相对独立,而与其它的Builder无关。
   3、 模式所建造的最终产品更易于控制。

咱们接下来,来尝试设计一个车的组装过程,这个是网上经典的案例,如下:

<?php
/** 
 * 建造者模式
 */ 
//需要建造的产品(product)
class Car
{/*{{{*/
  public $name;
  public $engine;//发动机
  public $chassis;//底盘
  public $body;//车身
  public $equipment;//电器设备
  public function setName($name)
  {
    $this->name = $name;
  }
  public function setEngine($engine)
  {
    $this->engine = $engine;
  }
  public function setChassis($chassis)
  {
    $this->chassis = $chassis;
  }
  public function setBody($body)
  {
    $this->body = $body;
  }
  public function setEquipment($equipment)
  {
    $this->equipment = $equipment;
  }
  public function show()
  {
    echo "名称:".$this->name."\r\n";
    echo "引擎:".$this->engine."\r\n";
    echo "底盘:".$this->chassis."\r\n";
    echo "车身:".$this->body."\r\n";
    echo "电子设备:".$this->equipment."\r\n";
  }
}/*}}}*/
//builder
interface IBuilder
{/*{{{*/
  public function builderName();
  public function builderEngine();
  public function builderChassis();
  public function builderBody();
  public function builderEquipment();
  public function getCar();
}/*}}}*/
//红旗车builder
class RedBuilder implements IBuilder
{/*{{{*/
  public $car;
  public function __construct()
  {
    $this->car = new Car();
  }
  public function builderName()
  {
    $this->car->setName('红旗'); 
  }
  public function builderEngine()
  {
    $this->car->setEngine('国产发动机'); 
  }
  public function builderChassis()
  {
    $this->car->setChassis('超大底盘'); 
  }
  public function builderBody()
  {
    $this->car->setBody('超大'); 
  }
  public function builderEquipment()
  {
    $this->car->setEquipment('电子设备'); 
  }
  public function getCar()
  {
    return $this->car;
  }
}/*}}}*/
//QQ车builder
class QQBuilder implements IBuilder
{/*{{{*/
  public $car;
  public function __construct()
  {
    $this->car = new Car();
  }
  public function builderName()
  {
    $this->car->setName('QQ'); 
  }
  public function builderEngine()
  {
    $this->car->setEngine('国产发动机'); 
  }
  public function builderChassis()
  {
    $this->car->setChassis('小底盘'); 
  }
  public function builderBody()
  {
    $this->car->setBody('小'); 
  }
  public function builderEquipment()
  {
    $this->car->setEquipment('电子设备'); 
  }
  public function getCar()
  {
    return $this->car;
  }
}/*}}}*/
//组装者(director)
class CarDirector
{/*{{{*/
  public function make(IBuilder $builder)
  {
    $builder->builderName();
    $builder->builderEngine();
    $builder->builderChassis();
    $builder->builderBody();
    $builder->builderEquipment();
    return $builder->getCar();
  }
}/*}}}*/
class Client
{/*{{{*/
  public static function main($argv)
  {
    $director = new CarDirector(); 
    $redBuilder = new RedBuilder();
    $car = $director->make($redBuilder);
    $car->show();
    echo "\r\n";
    $qqBuilder = new QQBuilder();
    $car = $director->make($qqBuilder);
    $car->show();
  }
}/*}}}*/
Client::main($argv);
?>

咱们可以观察到,建造者模式与工厂模式是极为相似的,并且总体上,建造者模式仅仅只比工厂模式多了一个“导演类”的角色,在建造者模式中,假如把这个导演类看做是最终调用的客户端,那么图中剩余的部分就可以看作是一个简单的工厂模式了。

与工厂模式相比,建造者模式一般用来创建更为复杂的对象,因为对象的创建过程更为复杂,因此将对象的创建过程独立出来组成一个新的类——导演类。也就是说,工厂模式是将对象的全部创建过程封装在工厂类中,由工厂类向客户端提供最终的产品;而建造者模式中,建造者类一般只提供产品类中各个组件的建造,而将具体建造过程交付给导演类。由导演类负责将各个组件按照特定的规则组建为产品,然后将组建好的产品交付给客户端。

好啦,本次记录就到这里了。

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
写一个用户在线显示的程序
Oct 09 PHP
php时间不正确的解决方法
Apr 09 PHP
php实现文件下载更能介绍
Nov 23 PHP
php设计模式之观察者模式的应用详解
May 21 PHP
php全局变量和类配合使用深刻理解
Jun 05 PHP
destoon官方标签大全
Jun 20 PHP
codeigniter发送邮件并打印调试信息的方法
Mar 21 PHP
Joomla调用系统自带编辑器的实现方法
May 05 PHP
Linux php 中文乱码的快速解决方法
May 13 PHP
PHP实现多级分类生成树的方法示例
Feb 07 PHP
php array_reverse 以相反的顺序返回数组实例代码
Apr 11 PHP
解决Laravel 不能创建 migration 的问题
Oct 09 PHP
PHP设计模式之适配器模式(Adapter)原理与用法详解
Dec 12 #PHP
PHP学习记录之常用的魔术常量详解
Dec 12 #PHP
记Laravel调用Gin接口调用formData上传文件的实现方法
Dec 12 #PHP
PHP命名空间(namespace)原理与用法详解
Dec 11 #PHP
在 Laravel 6 中缓存数据库查询结果的方法
Dec 11 #PHP
PHP超级全局变量【$GLOBALS,$_SERVER,$_REQUEST等】用法实例分析
Dec 11 #PHP
关于PHP5.6+版本“No input file specified”问题的解决
Dec 11 #PHP
You might like
简体中文转换为繁体中文的PHP函数
2006/10/09 PHP
php中判断文件空目录是否有读写权限的函数代码
2012/08/07 PHP
php实现随机显示图片方法汇总
2015/05/21 PHP
PHP的Yii框架中View视图的使用进阶
2016/03/29 PHP
php实现URL加密解密的方法
2016/11/17 PHP
laravel框架实现后台登录、退出功能示例
2019/10/31 PHP
javascript smipleChart 简单图标类
2011/01/12 Javascript
Js 时间函数getYear()的使用问题探讨
2013/04/01 Javascript
为指定的元素添加遮罩层的示例代码
2014/01/15 Javascript
javascript中验证大写字母、数字和中文
2014/01/15 Javascript
JS设置cookie、读取cookie、删除cookie
2015/04/17 Javascript
jQuery实现hover合成事件的方法
2015/08/06 Javascript
webix+springmvc session超时跳转登录页面
2016/10/30 Javascript
js实现点击按钮弹出上传文件的窗口
2016/12/23 Javascript
浅谈JavaScript的计时器对象
2016/12/26 Javascript
基于Vue实现页面切换左右滑动效果
2020/06/29 Javascript
bootstrap自定义样式之bootstrap实现侧边导航栏功能
2018/09/10 Javascript
Webpack4+Babel7+ES6兼容IE8的实现
2019/04/10 Javascript
JavaScript实现身份证验证代码实例
2019/08/26 Javascript
javascript中闭包closure的深入讲解
2021/03/03 Javascript
简单介绍Python中的RSS处理
2015/04/13 Python
python实现对一个完整url进行分割的方法
2015/04/29 Python
基于循环神经网络(RNN)的古诗生成器
2018/03/26 Python
Python延时操作实现方法示例
2018/08/14 Python
Python学习笔记之列表推导式实例分析
2019/08/13 Python
Python range、enumerate和zip函数用法详解
2019/09/11 Python
Python操作SQLite/MySQL/LMDB数据库的方法
2019/11/07 Python
python MultipartEncoder传输zip文件实例
2020/04/07 Python
美津浓美国官网:Mizuno美国
2018/08/07 全球购物
自我评价的范文
2014/02/02 职场文书
银行职员个人的工作自我评价
2014/02/15 职场文书
团委竞选演讲稿
2014/04/24 职场文书
管理岗位竞聘演讲稿
2014/08/18 职场文书
python3 hdf5文件 遍历代码
2021/05/19 Python
JavaCV实现照片马赛克效果
2022/01/22 Java/Android
如何利用python实现列表嵌套字典取值
2022/06/10 Python