php示例详解Constructor Prototype Pattern 原型模式


Posted in PHP onOctober 15, 2015

原型模式中主要角色

抽象原型(Prototype)角色:声明一个克隆自己的接口
具体原型(Concrete Prototype)角色:实现一个克隆自己的操作

当一个类大部分都是相同的只有部分是不同的时候,如果需要大量这个类的对象,每次都重复实例化那些相同的部分是开销很大的,而如果clone之前建立对象的那些相同的部分,就可以节约开销。

针对php的一种实现方式就是__construct()和initialize函数分开分别处理这个类的初始化,construct里面放prototype也就是公共的部分,initialize里面是每个对象特殊的部分。这样我们先建立一个类不initialize,以后每次clone这个类再进行initialize就可以了。

 在zend framework官方手册里面提到了这个http://framework.zend.com/manual/2.0/en/user-guide/database-and-models.html,但是没有细讲,下面我来分析一下

一、引入

在zf2的model里面有一个albumTable类,相当于一个操作数据库动作的助手类,里面用到了tablegateway。

为了每次初始化albumtable都是相同的一个类,将初始化工作放到了根目录的module.php文件的getServiceConfig(),其中用到工厂模式,并且通过回调函数,当每次ServiceManager($sm)需要实例化一个对象的时候会自动调用创建一个alumTable。下面代码我们可以看出,创建一个albumTable还需要用相同的方式创建一个AlbumTableGateWay,这个类就用到了我们所要讲的原型模式。

二、代码详解

public function getServiceConfig()
  {
    return array(
      'factories' => array(
        'Album\Model\AlbumTable' => function($sm) {
          $tableGateway = $sm->get('AlbumTableGateway');
          $table = new AlbumTable($tableGateway);
          return $table;
        },
        'AlbumTableGateway' => function ($sm) {
          $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
          $resultSetPrototype = new ResultSet();
          $resultSetPrototype->setArrayObjectPrototype(new Album());//这个就是一个不变的原型
          return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);//传入到TableGateWay的构造函数中去
        },
      ),
    );
  }

注意并不是TableGateWay运用了原型模式而是ResultSet这个类运用了。每当tablegateway调用select()或者insert()等方法的时候都会建立一个ResultSet用来表示结果,这些ResultSet中公共部分被clone,而独特的部分类如data就会被initialize。

三、更多代码示例

为了更清晰得了解这个原型,我们先抛开zend这个大框架,看一个完整的代码示例。示例来自

<a href="http://ralphschindler.com/2012/03/09/php-constructor-best-practices-and-the-prototype-pattern">PHP Constructor Best Practices And The Prototype Pattern</a>

这篇文章关于prototype pattern的部分前半部分其实是混杂怎样在构造函数中运用继承来提高扩展性,两个模式看起来可能不太好理解,我们直接看最后的代码关于prototype pattern的部分。

<?php
//框架中很常见的adapter类,用来适配各种数据库,封装一些基本数据库连接操作。
//相当于上面代码中的adapter类
class DbAdapter {
  public function fetchAllFromTable($table) {
    return $arrayOfData;
  }
}
//运用prototype pattern的类,注意construct和initialize是分开的
//相当于上面zend 代码里面的ResultSet类
class RowGateway {
  public function __construct(DbAdapter $dbAdapter, $tableName) {
    $this->dbAdapter = $dbAdapter;
    $this->tableName = $tableName;
  }
  public function initialize($data) {
    $this->data = $data;
  }
  /**
   * Both methods require access to the database adapter
   * to fulfill their duties
   */
  public function save() {}
  public function delete() {}
  public function refresh() {}
}
//相当于上面代码中的TableGateway类,关于gateway可以具体去了解一下。
class UserRepository {
  public function __construct(DbAdapter $dbAdapter, RowGateway $rowGatewayPrototype = null) {
    $this->dbAdapter = $dbAdapter;
    $this->rowGatewayPrototype = ($rowGatewayPrototype) ? new RowGateway($this->dbAdapter, 'user')
  }
  public function getUsers() {
    $rows = array();
    foreach ($this->dbAdapter->fetchAllFromTable('user') as $rowData) {
      $rows[] = $row = clone $this->rowGatewayPrototype;
      $row->initialize($rowData);
    }
    return $rows;
  }
}

这几个类其实和上面zend代码中的类是对应的

Dbadapter -- adpater

RowGateWay -- ResultSet

UserRepository - TableGateWay

具体看代码中的注释。

这里的RowGateWay可以很明显的看出在getusers中需要大量的实例化,那么原型模式就是很必要的了。

下面是运用这个类的代码

class ReadWriteRowGateway extends RowGateway {
  public function __construct(DbAdapter $readDbAdapter, DbAdapter $writeDbAdapter, $tableName) {
    $this->readDbAdapter = $readDbAdapter;
    parent::__construct($writeDbAdapter, $tableName);
  }
  public function refresh() {
    // utilize $this->readDbAdapter instead of $this->dbAdapter in RowGateway base implementation
  }
}
// usage:
$userRepository = new UserRepository(
  $dbAdapter,
  new ReadWriteRowGateway($readDbAdapter, $writeDbAdapter, 'user')
);
$users = $userRepository->getUsers();
$user = $users[0]; // instance of ReadWriteRowGateway with a specific row of data from the db

以上内容是小编给大家介绍的php示例详解Constructor Prototype Pattern 原型模式,希望大家喜欢。

PHP 相关文章推荐
php minixml详解
Jul 19 PHP
通过PHP current函数获取未知字符键名数组第一个元素的值
Jun 24 PHP
php设计模式之单例、多例设计模式的应用分析
Jun 30 PHP
处理(php-cgi.exe - FastCGI 进程超过了配置的请求超时时限)的问题
Jul 03 PHP
php绘图中显示不出图片的原因及解决
Mar 05 PHP
php截取字符串函数分享
Feb 02 PHP
php转换颜色为其反色的方法
Apr 27 PHP
PHP date函数常用时间处理方法
May 11 PHP
Zend Framework动作助手(Zend_Controller_Action_Helper)用法详解
Mar 05 PHP
PHP读取文本文件并逐行输出该行使用最多的字符与对应次数的方法
Nov 25 PHP
php统计数组不同元素的个数的实例方法
Sep 26 PHP
在laravel框架中实现封装公共方法全局调用
Oct 14 PHP
PHP经典面试题之设计模式(经常遇到)
Oct 15 #PHP
PHP面试题之文件目录操作
Oct 15 #PHP
php cli配置文件问题分析
Oct 15 #PHP
PHP+Mysql+jQuery实现发布微博程序 php篇
Oct 15 #PHP
10个php函数实用却不常见
Oct 13 #PHP
PHP实现连接设备、通讯和发送命令的方法
Oct 13 #PHP
PHP如何通过传引用的思想实现无限分类(代码简单)
Oct 13 #PHP
You might like
删除无限分类并同时删除它下面的所有子分类的方法
2010/08/08 PHP
简单的php写入数据库类代码分享
2011/07/26 PHP
php管理nginx虚拟主机shell脚本实例
2014/11/19 PHP
php正则表达式获取内容所有链接
2015/07/24 PHP
php 输出json及显示json中的中文汉字详解及实例
2016/11/09 PHP
PHP中$GLOBALS['HTTP_RAW_POST_DATA']和$_POST的区别分析
2017/07/03 PHP
PHP下载大文件失败并限制下载速度的实例代码
2019/05/10 PHP
PHP+iframe模拟Ajax上传文件功能示例
2019/07/02 PHP
通过url查找a元素并点击
2014/04/09 Javascript
让JavaScript和其它资源并发下载的方法
2014/10/16 Javascript
javascript中Array()数组函数详解
2015/08/23 Javascript
javascript合并表格单元格实例代码
2016/01/03 Javascript
简单实现js选项卡切换效果
2016/02/03 Javascript
javascript冒泡排序小结
2016/04/10 Javascript
使用jQuery中的wrap()函数操作HTML元素的教程
2016/05/24 Javascript
angularJS深拷贝详解
2017/03/23 Javascript
fullpage.js最后一屏滚动方式
2018/02/06 Javascript
jQuery+CSS实现的标签页效果示例【测试可用】
2018/08/14 jQuery
Vue使用Proxy监听所有接口状态的方法实现
2019/06/07 Javascript
使用webpack将ES6转化ES5的实现方法
2019/10/13 Javascript
python获取元素在数组中索引号的方法
2015/07/15 Python
查找python项目依赖并生成requirements.txt的方法
2018/07/10 Python
python实现的MySQL增删改查操作实例小结
2018/12/19 Python
Python 中PyQt5 点击主窗口弹出另一个窗口的实现方法
2019/07/04 Python
在Python中获取操作系统的进程信息
2019/08/27 Python
Python 测试框架unittest和pytest的优劣
2020/09/26 Python
python 实用工具状态机transitions
2020/11/21 Python
Python里面如何实现tuple和list的转换
2012/06/13 面试题
历史专业个人求职信范文
2013/12/07 职场文书
销售人员职业生涯规划范文
2014/03/01 职场文书
优秀毕业生就业推荐信
2014/05/22 职场文书
我心目中的好老师活动方案
2014/08/19 职场文书
雷锋的观后感
2015/06/10 职场文书
运动会200米广播稿
2015/08/19 职场文书
nginx共享内存的机制详解
2022/03/21 Servers
Nginx HTTP跳转至HTTPS
2022/05/15 Servers