PHP设计模式(三)建造者模式Builder实例详解【创建型】


Posted in PHP onMay 02, 2020

本文实例讲述了PHP设计模式:建造者模式Builder。分享给大家供大家参考,具体如下:

1. 概述

       在软件开发的过程中,当遇到一个“复杂的对象”的创建工作,该对象由一定各个部分的子对象用一定的算法构成,由于需求的变化,复杂对象的各个部分经常面临剧烈的变化,但将它们组合在一起的算法相对稳定。

       例子1:买肯德基

       典型的儿童餐包括一个主食,一个辅食,一杯饮料和一个玩具(例如汉堡、炸鸡、可乐和玩具车)。这些在不同的儿童餐中可以是不同的,但是组合成儿童餐的过程是相同的。

PHP设计模式(三)建造者模式Builder实例详解【创建型】

       客户端:顾客,想去买一套套餐(这里面包括汉堡,可乐,薯条),可以有1号和2号两种套餐供顾客选择。
       指导者角色:收银员。知道顾客想要买什么样的套餐,并告诉餐馆员工去准备套餐。
       建造者角色:餐馆员工。按照收银员的要求去准备具体的套餐,分别放入汉堡,可乐,薯条等。
       产品角色:最后的套餐,所有的东西放在同一个盘子里面。

        例子2:计算工资:工资的计算一般是:底薪+奖金-税。但底薪分为一级8000、二级6000、三级4000三个等级。根据岗位不同奖金的发放也不一样,管理及日常事务处理岗位(A类)每月根据领导及同事间的评议得分计算奖金,销售岗位(B类)则根据销售额发放提成。税金则根据奖金和底薪的数额进行计算。由此看出该工资的计算方式是比较稳定的构建算法,但对工资的每一部分都会根据不同的情况产生不同的算法,如何将客户端与变化巨烈的底薪、奖金和税金计算方式分离呢,这也比较适合用建造者模式。

2 . 问题

我们如何应对这种变化,如何提供一种“封装机制”来隔离“复杂对象的各个部”的变化,从而保持系统中的“稳定构建算法”而不随需求的变化而变化?

3. 解决方案

建造者模式: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

4. 适用性

在以下情况使用Builder模式

•当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。

•当构造过程必须允许被构造的对象有不同的表示时。

5. 结 构

此模式结构如下页上图所示。

PHP设计模式(三)建造者模式Builder实例详解【创建型】

6. 构建模式的组成

• 抽象建造者角色(Builder):为创建一个Product对象的各个部件指定抽象接口,以规范产品对象的各个组成成分的建造。一般而言,此角色规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建。

• 具体建造者(ConcreteBuilder)

1)实现Builder的接口以构造和装配该产品的各个部件。即实现抽象建造者角色Builder的方法。

2)定义并明确它所创建的表示,即针对不同的商业逻辑,具体化复杂对象的各部分的创建

3)  提供一个检索产品的接口

4)   构造一个使用Builder接口的对象即在指导者的调用下创建产品实例

指导者(Director):调用具体建造者角色以创建产品对象的各个部分。指导者并没有涉及具体产品类的信息,真正拥有具体产品的信息是具体建造者对象。它只负责保证对象各部分完整创建或按某种顺序创建。

产品角色(Product):建造中的复杂对象。它要包含那些定义组件的类,包括将这些组件装配成产品的接口。

7. 效果

Builder模式的主要效果:

1 ) 它使你可以改变一个产品的内部表示 Builder对象提供给导向器一个构造产品的抽象接口。该接口使得生成器可以隐藏这个产品的表示和内部结构。它同时也隐藏了该产品是如何装配的。因为产品是通过抽象接口构造的,你在改变该产品的内部表示时所要做的只是定义一个新的生成器。

2) 它将构造代码和表示代码分开 Builder模式通过封装一个复杂对象的创建和表示方式提高了对象的模块性。客户不需要知道定义产品内部结构的类的所有信息;这些类是不出现在Builder接口中的。每个Concrete Builder包含了创建和装配一个特定产品的所有代码。这些代码只需要写一次;然后不同的Director可以复用它以在相同部件集合的基础上构作不同的Product。

3 ) 它使你可对构造过程进行更精细的控制 Builder模式与一下子就生成产品的创建型模式不同,它是在导向者的控制下一步一步构造产品的。仅当该产品完成时导向者才从生成器中取回它。因此Builder接口相比其他创建型模式能更好的反映产品的构造过程。这使你可以更精细的控制构建过程,从而能更精细的控制所得产品的内部结构。

8. 实现:

指导者:收银员

<?php
 /**
 * 指导者:收银员
 *
 */
 class DirectorCashier
 {
 /**
  * 收银餐馆员工返回的食物
  *
  */
 public function buildFood(Builder $builder) {
  $builder->buildPart1();
  $builder->buildPart2();
 }
 }

抽象建造者:

/**
 * 抽象建造者
 *
 */
 abstract class Builder
 {
 /**
  * 创建产品的第一部分
   */
 public abstract function buildPart1();
 
 /**
  * 
  * 创建产品的第二部分
   */
 public abstract function buildPart2();
 
 /**
  * 
  * 返回产品
   */
 public abstract function getProduct();
 }

具体建造者类:

/**
 * 具体建造者类:餐馆员工,返回的套餐是:汉堡两个+饮料一个
 *
 */
 class ConcreteBuilder1 extends Builder
 {
 protected $_product = null;//产品对象
 function __construct(){
  $this->_product = new Product();
 }
 
 /**
  * 创建产品的第一部分::汉堡=2
   */
 public function buildPart1()
 {
  $this->_product->add('Hamburger',2);
 }
 /**
  * 
  * 创建产品的第二部分:
   */
 public function buildPart2()
 {
  $this->_product->add('Drink', 1);
 }
 /**
  * 返回产品对象 :
  * 
  */
 public function getProduct() {
  return $this->_product;
 }
 }
/**
 * 具体建造者类:餐馆员工,汉堡1个+饮料2个
 *
 */
 class ConcreteBuilder2 extends Builder
 {
 protected $_product = null;//产品对象
 function __construct(){
  $this->_product = new Product();
 }
 
 /**
  * 创建产品的第一部分:汉堡
   */
 public function buildPart1()
 {
  $this->_product->add('Hamburger', 1);
 }
 /**
  * 
  * 创建产品的第二部分:drink=2
   */
 public function buildPart2()
 {
  $this->_product->add('Drink', 2);
 }
 /**
  * 返回产品对象 :
  * 
  */
 public function getProduct() {
  return $this->_product;
 }
 }

产品类:

/**
 * 产品类
 */
 class Product
 {
 public $products = array();
 /**
  * 添加具体产品
  */
 public function add($name, $value) {
  $this->products[$name] = $value;
 }
 /**
  * 给顾客查看产品
  */
 public function showToClient()
 {
  foreach ($this->products as $key => $v) {
  echo $key , '=' , $v ,'<br>';
  }
 }
 }

客户程序:

//客户程序
 class Client
 {
 /**
  * 顾客购买套餐
  *
  */
 public function buy($type) {
  //指导者,收银员
  $director = new DirectorCashier(); 
  //餐馆员工,收银员
     $class = new ReflectionClass('ConcreteBuilder' .$type );
     $concreteBuilder = $class->newInstanceArgs();
     //收银员组合员工返回的食物
     $director->buildFood($concreteBuilder);
     //返回给顾客
     $concreteBuilder->getProduct()->showToClient();
 }
 }
 //测试
 ini_set('display_errors', 'On');
 $c = new Client();
 $c->buy(1);//购买套餐1
 $c->buy(2);//购买套餐1

9. 建造者模式的优点

       首先,建造者模式的封装性很好。使用建造者模式可以有效的封装变化,在使用建造者模式的场景中,一般产品类和建造者类是比较稳定的,因此,将主要的业务逻辑封装在导演类中对整体而言可以取得比较好的稳定性。

       其次,建造者模式很容易进行扩展。如果有新的需求,通过实现一个新的建造者类就可以完成,基本上不用修改之前已经测试通过的代码,因此也就不会对原有功能引入风险。

10. 建造者模式与工厂模式的区别

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

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

11. 总结

      建造者模式与工厂模式类似,他们都是建造者模式,适用的场景也很相似。一般来说,如果产品的建造很复杂,那么请用工厂模式;如果产品的建造更复杂,那么请用建造者模式。

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

PHP 相关文章推荐
ThinkPHP php 框架学习笔记
Oct 30 PHP
php中XMLHttpRequest(Ajax)不能设置自定义的Referer的解决方法
Nov 26 PHP
php中邮箱地址正则表达式实现与详解
Apr 24 PHP
使用Smarty 获取当前日期时间和格式化日期时间的方法详解
Jun 18 PHP
php使用function_exists判断函数可用的方法
Nov 19 PHP
php比较两个字符串长度的方法
Jul 13 PHP
[原创]php使用curl判断网页404(不存在)的方法
Jun 23 PHP
php结合mysql与mysqli扩展处理事务的方法
Jun 29 PHP
关于PHP中字符串与多进制转换函数的实例代码
Nov 03 PHP
php实现的简单数据库操作Model类
Nov 16 PHP
php获取目录下所有文件及目录(多种方法)(推荐)
May 14 PHP
PHP Swoole异步读取、写入文件操作示例
Oct 24 PHP
PHP设计模式(一)工厂模式Factory实例详解【创建型】
May 02 #PHP
PHP设计模式概论【概念、分类、原则等】
May 01 #PHP
PHP设计模式之 策略模式Strategy详解【对象行为型】
May 01 #PHP
php如何获取Http请求
Apr 30 #PHP
PHP 命名空间和自动加载原理与用法实例分析
Apr 29 #PHP
Yii使用EasyWechat实现小程序获取用户的openID的方法
Apr 29 #PHP
Thinkphp集成抖音SDK的实现方法
Apr 28 #PHP
You might like
php代码优化及php相关问题总结
2006/10/09 PHP
基于mysql的bbs设计(四)
2006/10/09 PHP
php 动态执行带有参数的类方法
2009/04/10 PHP
php学习笔记 数组遍历实现代码
2011/06/09 PHP
phplot生成图片类用法详解
2015/01/06 PHP
从面试题学习Javascript 面向对象(创建对象)
2012/03/30 Javascript
JS注册/移除事件处理程序(ExtJS应用程序设计实战)
2013/05/07 Javascript
Javascript中的方法和匿名方法实例详解
2015/06/13 Javascript
JavaScript知识点总结(十一)之js中的Object类详解
2016/05/31 Javascript
Layer弹出层动态获取数据的方法
2018/08/20 Javascript
详解webpack 最简打包结果分析
2019/02/20 Javascript
vue-router跳转时打开新页面的两种方法
2019/07/29 Javascript
Javascript实现单选框效果
2020/12/09 Javascript
[01:32]DOTA2次级联赛——首支职业女子战队选拔赛全记录
2014/10/23 DOTA
举例讲解Python中的身份运算符的使用方法
2015/10/13 Python
实例讲解Python设计模式编程之工厂方法模式的使用
2016/03/02 Python
Python基础教程之正则表达式基本语法以及re模块
2016/03/25 Python
python定时利用QQ邮件发送天气预报的实例
2017/11/17 Python
python 接口返回的json字符串实例
2018/03/27 Python
Python中常用的8种字符串操作方法
2019/05/06 Python
python 一篇文章搞懂装饰器所有用法(建议收藏)
2019/08/23 Python
python标准库OS模块详解
2020/03/10 Python
Python中用xlwt制作表格实例讲解
2020/11/05 Python
为2021年的第一场雪锦上添花:用matplotlib绘制雪花和雪景
2021/01/05 Python
美国最大的网上冲印店:Shutterfly
2017/01/01 全球购物
马德里著名的运动鞋商店:NOIRFONCE
2019/04/12 全球购物
汽车驾驶求职信
2013/10/25 职场文书
《母亲的恩情》教学反思
2014/02/13 职场文书
《春笋》教学反思
2014/04/15 职场文书
《闻一多先生的说和做》教学反思
2014/04/28 职场文书
微笑面对生活演讲稿
2014/05/13 职场文书
承诺书格式范文
2014/06/03 职场文书
思想作风纪律整顿心得体会
2014/09/04 职场文书
舌尖上的中国观后感
2015/06/02 职场文书
创业分两种人:那么哪些适合创业?,哪些适合不适合创业呢?
2019/08/23 职场文书
导游词之江苏同里古镇
2019/11/18 职场文书