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 相关文章推荐
ionCube 一款类似zend的PHP加密/解密工具
Jul 25 PHP
PHP中simplexml_load_string函数使用说明
Jan 01 PHP
php学习之function的用法
Jul 14 PHP
php模板函数 正则实现代码
Oct 15 PHP
利用PHP函数计算中英文字符串长度的方法
Nov 11 PHP
php实现的SESSION类
Dec 02 PHP
php使用Image Magick将PDF文件转换为JPG文件的方法
Apr 01 PHP
php通过exif_read_data函数获取图片的exif信息
May 21 PHP
PHP生成随机密码方法汇总
Aug 27 PHP
深入理解PHP类的自动载入机制
Sep 16 PHP
php获取flash尺寸详细数据的方法
Nov 12 PHP
php日志函数error_log用法实例分析
Sep 23 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
PHP 5.0对象模型深度探索之属性和方法
2008/03/27 PHP
php中json_encode UTF-8中文乱码的更好解决方法
2014/09/28 PHP
php post大量数据时发现数据丢失问题解决方法
2015/06/20 PHP
thinkphp验证码的实现(form、ajax实现验证)
2016/07/28 PHP
ExtJS 2.2.1的grid控件在ie6中的显示问题
2009/05/04 Javascript
Jquery弹出窗口插件 LeanModal的使用方法
2012/03/10 Javascript
jquery快捷动态绑定键盘事件的操作函数代码
2013/10/17 Javascript
JQuery对表格进行操作的常用技巧总结
2014/04/23 Javascript
javascript实现unicode与ASCII相互转换的方法
2015/12/10 Javascript
JQuery EasyUI Layout 在from布局自适应窗口大小的实现方法
2016/05/28 Javascript
input输入密码变黑点密文的实现方法
2017/01/09 Javascript
jQuery的ztree仿windows文件新建和拖拽功能的实现代码
2018/12/05 jQuery
Vue 刷新当前路由的实现代码
2019/09/26 Javascript
vue移动端模态框(可传参)的实现
2019/11/20 Javascript
JQuery常用简单动画操作方法回顾与总结
2019/12/07 jQuery
[01:04:14]VP vs TNC 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/20 DOTA
Python用Bottle轻量级框架进行Web开发
2016/06/08 Python
Python中的time模块与datetime模块用法总结
2016/06/30 Python
对Python random模块打乱数组顺序的实例讲解
2018/11/08 Python
Python将json文件写入ES数据库的方法
2019/04/10 Python
python输出电脑上所有的串口名的方法
2019/07/02 Python
Python3实现建造者模式的示例代码
2020/06/28 Python
Gap工厂店:Gap Factory
2017/11/02 全球购物
Ibatis的核心配置文件都有什么
2014/09/08 面试题
北京-环亚运商测试题.net程序员初步测试题
2013/05/28 面试题
工程造价专业大专生求职信
2013/10/06 职场文书
毕业生的自我鉴定
2013/10/29 职场文书
历史专业个人求职信分享
2013/12/20 职场文书
优秀企业获奖感言
2014/02/01 职场文书
优秀大学生职业生涯规划书
2014/02/27 职场文书
主要领导对照检查材料
2014/08/26 职场文书
暑假学习心得体会
2014/09/02 职场文书
公证书格式
2015/01/23 职场文书
办公室主任岗位竞聘书
2015/09/15 职场文书
2016年记者节感言
2015/12/08 职场文书
《兰兰过桥》教学反思
2016/02/20 职场文书