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 相关文章推荐
从php核心代码分析require和include的区别
Jan 02 PHP
PHP及Zend Engine的线程安全模型分析
Nov 10 PHP
Ubuntu中启用php的mail()函数并解决发送邮件速度慢问题
Mar 27 PHP
php生成圆角图片的方法
Apr 07 PHP
Yii控制器中filter过滤器用法分析
Jul 15 PHP
thinkPHP模板中for循环与switch语句用法示例
Nov 30 PHP
PHP实现获取第一个中文首字母并进行排序的方法
May 09 PHP
php快速导入大量数据的实例方法
Sep 23 PHP
解决Laravel5.2 Auth认证退出失效的问题
Oct 14 PHP
解决tp5在nginx下修改配置访问的问题
Oct 16 PHP
php 的多进程操作实践案例分析
Feb 28 PHP
6个常见的 PHP 安全性攻击实例和阻止方法
Dec 16 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 MemCached高级缓存配置图文教程
2010/08/05 PHP
浅析echo(),print(),print_r(),return之间的区别
2013/11/27 PHP
ThinkPHP框架整合微信支付之Native 扫码支付模式二图文详解
2019/04/09 PHP
php+js实现点赞功能的示例详解
2020/08/07 PHP
jquery 最简单易用的表单验证插件
2010/02/27 Javascript
方便实用的jQuery checkbox复选框全选功能简单实例
2013/10/09 Javascript
javascript对下拉列表框(select)的操作实例讲解
2013/11/29 Javascript
js判断url是否有效的两种方法
2014/03/04 Javascript
Javascript中的异步编程规范Promises/A详细介绍
2014/06/06 Javascript
理解javascript正则表达式
2016/03/08 Javascript
浅析JS操作DOM的一些常用方法
2016/05/13 Javascript
浅谈js的html元素的父节点,子节点
2016/08/06 Javascript
点击页面任何位置隐藏div的实现方法
2016/09/05 Javascript
深入学习Bootstrap表单
2016/12/13 Javascript
Vue.js使用$.ajax和vue-resource实现OAuth的注册、登录、注销和API调用
2017/05/10 Javascript
微信小程序实现图片上传
2019/05/23 Javascript
OpenLayers3实现图层控件功能
2020/09/25 Javascript
使用vue构建多页面应用的示例
2020/10/22 Javascript
js实现电灯开关效果
2021/01/19 Javascript
Python天气预报采集器实现代码(网页爬虫)
2012/10/07 Python
python模拟登录百度贴吧(百度贴吧登录)实例
2013/12/18 Python
列举Python中吸引人的一些特性
2015/04/09 Python
深入解读Python解析XML的几种方式
2016/02/16 Python
python opencv人脸检测提取及保存方法
2018/08/03 Python
python 循环读取txt文档 并转换成csv的方法
2018/10/26 Python
python修改FTP服务器上的文件名
2019/09/11 Python
Python-openCV开运算实例
2020/07/05 Python
使用darknet框架的imagenet数据分类预训练操作
2020/07/07 Python
python list等分并从等分的子集中随机选取一个数
2020/11/16 Python
日本最大的购物网站:日本乐天市场(Rakuten Ichiba)
2020/11/04 全球购物
database面试题
2013/03/28 面试题
幼儿园安全检查制度
2014/01/30 职场文书
电气个人求职信范文
2014/02/04 职场文书
计算机网络工程专业职业生涯规划书
2014/03/10 职场文书
2014年学校工会工作总结
2014/12/06 职场文书
2015年酒店销售部工作总结
2015/07/24 职场文书