PHP设计模式(四)原型模式Prototype实例详解【创建型】


Posted in PHP onMay 02, 2020

本文实例讲述了PHP设计模式:原型模式Prototype。分享给大家供大家参考,具体如下:

1.   概述

我们都知道,创建型模式一般是用来创建一个新的对象,然后我们使用这个对象完成一些对象的操作,我们通过原型模式可以快速的创建一个对象而不需要提供专门的new()操作就可以快速完成对象的创建,这无疑是一种非常有效的方式,快速的创建一个新的对象。

例子1:孙悟空拔下一嘬猴毛,轻轻一吹就会变出好多的孙悟空来。

例子2:寄个快递

下面是一个邮寄快递的场景:
“给我寄个快递。”顾客说。
“寄往什么地方?寄给……?”你问。
“和上次差不多一样,只是邮寄给另外一个地址,这里是邮寄地址……”顾客一边说一边把写有邮寄地址的纸条给你。
“好!”你愉快地答应,因为你保存了用户的以前邮寄信息,只要复制这些数据,然后通过简单的修改就可以快速地创建新的快递数据了。

2. 问题

当对象的构造函数非常复杂,在生成新对象的时候非常耗时间、耗资源的情况?我们是怎么来创建呢?

3. 解决方案

       通过复制(克隆、拷贝)一个指定类型的对象来创建更多同类型的对象。这个指定的对象可被称为“原型”对象,也就是通过复制原型对象来得到更多同类型的对象。即原型设计模式。在php的很多模板库,都用到clone。如smarty等。

4. 适用性

原型模式的主要思想是基于现有的对象克隆一个新的对象出来,一般是有对象的内部提供克隆的方法,通过该方法返回一个对象的副本,这种创建对象的方式,相比我们之前说的几类创建型模式还是有区别的,之前的讲述的工厂模式与抽象工厂都是通过工厂封装具体的new操作的过程,返回一个新的对象,有的时候我们通过这样的创建工厂创建对象不值得,特别是以下的几个场景的时候,可能使用原型模式更简单也效率更高。

• 1)当一个系统应该独立于它的产品创建、构成和表示时,要使用 Prototype模式

• 2)当要实例化的类是在运行时刻指定时,例如,通过动态装载;

• 3)为了避免创建一个与产品类层次平行的工厂类层次时

• 4)当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。(也就是当我们在处理一些对象比较简单,并且对象之间的区别很小,可能只是很固定的几个属性不同的时候,可能我们使用原型模式更合适)。

5. 结构

     原型模式结构如下页上图所示:

PHP设计模式(四)原型模式Prototype实例详解【创建型】

6. 组成

客户(Client)角色:使用原型对象的客户程序
抽象原型(Prototype)角色:规定了具体原型对象必须实现的接口(如果要提供深拷贝,则必须具有实现clone的规定)
具体原型(ConcretePrototype):从抽象原型派生而来,是客户程序使用的对象,即被复制的对象。此角色需要实现抽象原型角色所要求的接口。

7. 效果

Prototype模式有许多和Abstract Factory模式 和 Builder模式一样的效果:它对客户隐藏了具体的产品类,因此减少了客户知道的名字的数目。此外,这些模式使客户无需改变即可使用与特定应用相关的类。

下面列出Prototype模式的另外一些优点。

1 ) 运行时刻增加和删除产品: Prototype允许只通过客户注册原型实例就可以将一个新的具体产品类并入系统。它比其他创建型模式更为灵活,因为客户可以在运行时刻建立和删除原型。
2 ) 改变值以指定新对象: 高度动态的系统允许你通过对象复合定义新的行为—例如,通过为一个对象变量指定值—并且不定义新的类。你通过实例化已有类并且将这些实例注册为客户对象的原型,就可以有效定义新类别的对象。客户可以将职责代理给原型,从而表现出新的行为。这种设计使得用户无需编程即可定义新“类” 。实际上,克隆一个原型类似于实例化一个类。Prototype模式可以极大的减少系统所需要的类的数目。
3) 改变结构以指定新对象:许多应用由部件和子部件来创建对象。
4) 减少子类的构造 Factory Method 经常产生一个与产品类层次平行的 Creator类层次。Prototype模式使得你克隆一个原型而不是请求一个工厂方法去产生一个新的对象。因此你根本不需要Creator类层次。这一优点主要适用于像 C + +这样不将类作为一级类对象的语言。像Smalltalk和Objective C这样的语言从中获益较少,因为你总是可以用一个类对象作为生成者。在这些语言中,类对象已经起到原型一样的作用了。
5) 用类动态配置应用 一些运行时刻环境允许你动态将类装载到应用中。在像 C + +这样的语言中,Prototype模式是利用这种功能的关键。一个希望创建动态载入类的实例的应用不能静态引用类的构造器。而应该由运行环境在载入时自动创建每个类的实例,并用原型管理器来注册这个实例(参见实现一节) 。这样应用就可以向原型管理器请求新装载的类的实例,这些类原本并没有和程序相连接。 E T + +应用框架[ W G M 8 8 ]有一个运行系统就是使用这一方案的。

Prototype的主要缺陷是每一个Prototype的子类都必须实现clone操作,这可能很困难。
例如,当所考虑的类已经存在时就难以新增 clone操作。当内部包括一些不支持拷贝或有循环引用的对象时,实现克隆可能也会很困难的。

8. 实现

<?php
/**
 * 原型模式 
 */
 
/**
 * 抽象原型角色
 */
interface Prototype {
  public function copy();
}
 
/**
 * 具体原型角色
 */
class ConcretePrototype implements Prototype{
 
  private $_name;
 
  public function __construct($name) {
    $this->_name = $name;
  }
 
  public function setName($name) {
    $this->_name = $name;
  }
 
  public function getName() {
    return $this->_name;
  }
 
  public function copy() {
    /** 深拷贝 */
    return clone $this;  
    /** 浅拷贝 */
    //return $this;  
  }
}
 
class Client {
 
   /**
   * Main program.
   */
  public static function main() {
    $object1 = new ConcretePrototype(11);
    $object_copy = $object1->copy();
 
    var_dump($object1->getName());
    echo '<br />';
    var_dump($object_copy->getName());
    echo '<br />';
 
    $object1->setName(22);
    var_dump($object1->getName());
    echo '<br />';
    var_dump($object_copy->getName());
    echo '<br />';
  }
}
Client::main();
?>

9. 浅拷贝和深拷贝

原型模式的原理图:

PHP设计模式(四)原型模式Prototype实例详解【创建型】

浅拷贝

被拷贝对象的所有变量都含有与原对象相同的值,而且对其他对象的引用仍然是指向原来的对象。即浅拷贝只负责当前对象实例,对引用的对象不做拷贝。

浅复制后的对象和对象副本的情况:

PHP设计模式(四)原型模式Prototype实例详解【创建型】

深拷贝

被拷贝对象的所有的变量都含有与原来对象相同的值,除了那些引用其他对象的变量。那些引用其他对象的变量将指向一个被拷贝的新对象,而不再是原有那些被引用对象。即 深拷贝把要拷贝的对象所引用的对象也都拷贝了一次,而这种对被引用到的对象拷贝叫做间接拷贝。

深复制的对象和对象副本的情况:

PHP设计模式(四)原型模式Prototype实例详解【创建型】

深拷贝要深入到多少层,是一个不确定的问题。

在决定以深拷贝的方式拷贝一个对象的时候,必须决定对间接拷贝的对象是采取浅拷贝还是深拷贝还是继续采用深拷贝。

因此,在采取深拷贝时,需要决定多深才算深。此外,在深拷贝的过程中,很可能会出现循环引用的问题。

10. 带Prototype Manager的原型模式

     原型模式的第二种形式是带原型管理器的原型模式,其UML图如下:

PHP设计模式(四)原型模式Prototype实例详解【创建型】

       原型管理器(Prototype Manager)角色:创建具体原型类的对象,并记录每一个被创建的对象。

       下面这个例子演示了在原型管理器中存储用户预先定义的颜色原型,客户通过原型管理器克隆颜色对象。

<?php
/**
 * abstract Prototype
 *
 */
abstract class ColorPrototype
{
 //Methods
 abstract function copy();
}
 
/**
 * Concrete Prototype
 *
 */
class Color extends ColorPrototype{
 //Fields
 private $red;
 private $green;
 private $blue;
 //Constructors
 function __construct( $red, $green, $red) {
  $this->red = $red;
  $this->green = $green;
  $this->blue = $red;
 }
 /**
  * set red
  *
  * @param unknown_type $red
  */
 public function setRed($red) {
  $this->red = $red;
 }
 
 /**
  * get red
  *
  */
 public function getRed(){
  return $this->red;
 }
 /**
  *set Green
  *
  * @param $green
  */
 public function setGreen($green) {
  $this->green = $green;
 }
 /**
  * get Green
  *
  * @return unknown
  */
 public function getGreen() {
  return $this->green ;
 }
 /**
  *set Blue
  *
  * @param $Blue
   */
 public function setBlue($Blue) {
  $this->blue = $Blue;
 }
 /**
  * get Blue
  *
  * @return unknown
  */
 public function getBlue() {
  return $this->blue ;
 }
 
 /**
 * Enter description here...
 *
 * @return unknown
 */
 function copy(){
 return clone $this;
 }
 
 function display() {
 echo $this->red , ',', $this->green, ',', $this->blue ,'<br>';
 }
}
/**
 * Enter description here...
 *
 */
class ColorManager
{
 // Fields
 static $colors = array();
 // Indexers
 public static function add($name, $value){
 self::$colors[$name] = $value;
 }
 
 public static function getCopy($name) {
 return  self::$colors[$name]->copy();
 }
}
/**
 *Client
 *
 */
class Client
{
 public static function Main()
 {
 //原型:白色
 ColorManager::add("white", new Color( 255, 0, 0 ));
 
 //红色可以由原型白色对象得到,只是重新修改白色: r
 $red = ColorManager::getCopy('white');
 $red->setRed(255);
 $red->display();
 
 //绿色可以由原型白色对象得到,只是重新修改白色: g
 $green = ColorManager::getCopy('white');
 $green->setGreen(255);
 $green->display();
 
 //绿色可以由原型白色对象得到,只是重新修改白色: b
 $Blue = ColorManager::getCopy('white');
 $Blue->setBlue(255);
 $Blue->display();
 }
}
ini_set('display_errors', 'On');
error_reporting(E_ALL & ~ E_DEPRECATED);
Client::Main();
?>

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

PHP 相关文章推荐
第四节--构造函数和析构函数
Nov 16 PHP
php下使用无限生命期Session的方法
Mar 16 PHP
全新的PDO数据库操作类php版(仅适用Mysql)
Jul 22 PHP
php对称加密算法示例
May 07 PHP
VB中的RasEnumConnections函数返回632错误解决方法
Jul 29 PHP
php无限极分类递归排序实现方法
Nov 11 PHP
ThinkPHP函数详解之M方法和R方法
Sep 10 PHP
PHP中如何防止外部恶意提交调用ajax接口
Apr 11 PHP
PHP将身份证正反面两张照片合成一张图片的代码
Apr 08 PHP
PHP 7安装调试工具Xdebug扩展的方法教程
Jun 17 PHP
在 Laravel 项目中使用 webpack-encore的方法
Jul 21 PHP
PHP实现rar解压读取扩展包小结
Jun 03 PHP
PHP设计模式(三)建造者模式Builder实例详解【创建型】
May 02 #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
You might like
解析php curl_setopt 函数的相关应用及介绍
2013/06/17 PHP
Linux(CentOS)下PHP扩展PDO编译安装的方法
2016/04/07 PHP
PHP实现的分页类定义与用法示例
2017/07/05 PHP
Laravel 实现密码重置功能
2018/02/23 PHP
讨论javascript(一)工厂方式 js面象对象的定义方法
2009/12/15 Javascript
javascript 动态调整图片尺寸实现代码
2009/12/28 Javascript
表格奇偶行设置不同颜色的核心JS代码
2013/12/24 Javascript
node.js中的定时器nextTick()和setImmediate()区别分析
2014/11/26 Javascript
node.js中的fs.fstatSync方法使用说明
2014/12/15 Javascript
node中socket.io的事件使用详解
2014/12/15 Javascript
javascript修改图片src的方法
2015/01/27 Javascript
简介JavaScript中Math.LOG10E属性的使用
2015/06/14 Javascript
Javascript将数字转化成为货币格式字符串
2016/06/22 Javascript
Bootstrap登陆注册页面开发教程
2016/07/12 Javascript
node.js缺少mysql模块运行报错的解决方法
2016/11/13 Javascript
使用JS实现气泡跟随鼠标移动的动画效果
2017/09/16 Javascript
jquery radio 动态控制选中失效问题的解决方法
2018/02/28 jQuery
JavaScript设计模式之构造函数模式实例教程
2018/07/02 Javascript
Django+vue跨域问题解决的详细步骤
2019/01/20 Javascript
Angular7.2.7路由使用初体验
2019/03/01 Javascript
搭建Vue从Vue-cli到router路由护卫的实现
2019/11/14 Javascript
js实现多图和单图上传显示
2019/12/18 Javascript
基于vue.js实现购物车
2020/01/15 Javascript
Python 的 Socket 编程
2015/03/24 Python
用Python编写web API的教程
2015/04/30 Python
python删除指定类型(或非指定)的文件实例详解
2015/07/06 Python
在Django的视图中使用数据库查询的方法
2015/07/16 Python
python3基于OpenCV实现证件照背景替换
2018/07/18 Python
Pycharm和Idea支持的vim插件的方法
2020/02/21 Python
Python 线性回归分析以及评价指标详解
2020/04/02 Python
详解Python中string模块除去Str还剩下什么
2020/11/30 Python
css 省略号 css3让多余的字符串消失并附加省略号的实现代码
2013/02/07 HTML / CSS
3的组成教学反思
2014/04/30 职场文书
2014最新预备党员思想汇报范文:中国梦,我的梦
2014/10/25 职场文书
新郎接新娘保证书
2015/05/08 职场文书
2015医院个人工作总结范文
2015/05/21 职场文书