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 正则 过滤html 的超链接
Jun 02 PHP
PHP面向对象之旅:深入理解static变量与方法
Jan 06 PHP
header导出Excel应用示例
Jan 24 PHP
PHP生成自定义长度随机字符串的函数分享
May 04 PHP
PHP调用wsdl文件类型的接口代码分享
Nov 19 PHP
smarty模板引擎中自定义函数的方法
Jan 22 PHP
php绘图之生成饼状图的方法
Jan 24 PHP
php实现用已经过去多长时间的方式显示时间
Jun 05 PHP
Zend Framework教程之Zend_Config_Xml用法分析
Mar 23 PHP
PHP实现微信JS-SDK接口选择相册及拍照并上传的方法
Dec 05 PHP
Yii框架数据库查询、增加、删除操作示例
Oct 14 PHP
Laravel Reponse响应客户端示例详解
Sep 03 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用mysql数据库存储session的代码
2010/03/05 PHP
php解决约瑟夫环示例
2014/04/09 PHP
Javascript 构造函数 实例分析
2008/11/26 Javascript
在IE,Firefox,Safari,Chrome,Opera浏览器上调试javascript
2008/12/02 Javascript
这段js代码得节约你多少时间
2011/12/20 Javascript
ExtJS DOM元素操作经验分享
2013/08/28 Javascript
javascript实现带节日和农历的日历特效
2015/02/01 Javascript
JS实现判断碰撞的方法
2015/02/11 Javascript
jQuery在ul中显示某个li索引号的方法
2015/03/17 Javascript
javascript生成不重复的随机数
2015/07/17 Javascript
Jquery修改image的src属性,图片不加载问题的解决方法
2016/05/17 Javascript
js图片加载效果实例代码(延迟加载+瀑布流加载)
2017/05/12 Javascript
node实现基于token的身份验证
2018/04/09 Javascript
使用Vue自定义指令实现Select组件
2018/05/24 Javascript
对Vue.js之事件的绑定(v-on: 或者 @ )详解
2018/09/15 Javascript
jQuery+vue.js实现的多选下拉列表功能示例
2019/01/15 jQuery
[01:01:52]完美世界DOTA2联赛PWL S2 GXR vs Magma 第二场 11.25
2020/11/26 DOTA
使用Django Form解决表单数据无法动态刷新的两种方法
2017/07/14 Python
Python Numpy库安装与基本操作示例
2019/01/08 Python
Pytorch十九种损失函数的使用详解
2020/04/29 Python
Django自带用户认证系统使用方法解析
2020/11/12 Python
Web前端绘制0.5像素的几种方法
2017/08/11 HTML / CSS
HTML5本地数据库基础操作详解
2016/04/26 HTML / CSS
THE OUTNET英国官网:国际设计师品牌折扣网站
2016/08/14 全球购物
美国杂志订阅折扣与优惠网站:Magazines.com
2016/08/31 全球购物
美国保健品专家:Life Extension
2018/05/04 全球购物
编程实现去掉XML的重复结点
2014/05/28 面试题
大学生军训自我评价分享
2013/11/09 职场文书
劳动竞赛活动方案
2014/02/20 职场文书
银行党员批评与自我批评
2014/10/15 职场文书
2015元旦节寄语
2014/12/08 职场文书
大雁塔英文导游词
2015/02/10 职场文书
比赛口号霸气押韵
2015/12/24 职场文书
Java Spring Boot 正确读取配置文件中的属性的值
2022/04/20 Java/Android
Python中的协程(Coroutine)操作模块(greenlet、gevent)
2022/05/30 Python
Python中的 enumerate和zip详情
2022/05/30 Python