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获取当前网址url并替换参数或网址的方法
Jun 06 PHP
让Nginx支持ThinkPHP的URL重写和PATHINFO的方法分享
Aug 08 PHP
关于使用key/value数据库redis和TTSERVER的心得体会
Jun 28 PHP
php function用法如何递归及return和echo区别
Mar 07 PHP
浅谈使用 PHP 进行手机 APP 开发(API 接口开发)
Aug 11 PHP
PHP面向对象精要总结
Nov 07 PHP
php隐藏IP地址后两位显示为星号的方法
Nov 21 PHP
php实现判断访问来路是否为搜索引擎机器人的方法
Apr 15 PHP
PHP网站建设的流程与步骤分享
Sep 25 PHP
PHP中md5()函数的用法讲解
Mar 30 PHP
PHP fopen中文文件名乱码问题解决方案
Oct 28 PHP
PhpSpreadsheet中文文档 | Spreadsheet操作教程实例
Apr 01 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
实用函数4
2007/11/08 PHP
PHP提示Deprecated: mysql_connect(): The mysql extension is deprecated的解决方法
2014/08/28 PHP
php实现多维数组中每个单元值(数字)翻倍的方法
2015/02/16 PHP
利用PHP抓取百度阅读的方法示例
2016/12/18 PHP
看了就知道什么是JSON
2007/12/09 Javascript
jquery tools 系列 scrollable学习
2009/09/06 Javascript
Jquery Validate 正则表达式实用验证代码大全
2013/08/23 Javascript
JS简单获取当前年月日星期的方法示例
2017/02/07 Javascript
bootstrap-table实现服务器分页的示例 (spring 后台)
2017/09/01 Javascript
checkbox:click事件触发span元素内容改变的方法
2017/09/11 Javascript
浅谈vue中数据双向绑定的实现原理
2017/09/14 Javascript
jQuery图片加载失败替换默认图片方法汇总
2017/11/29 jQuery
Vue 3.0 前瞻Vue Function API新特性体验
2019/08/12 Javascript
在vue中created、mounted等方法使用小结
2020/07/21 Javascript
vue2.0 watch里面的 deep和immediate用法说明
2020/10/30 Javascript
vue 授权获取微信openId操作
2020/11/13 Javascript
简述Python中的面向对象编程的概念
2015/04/27 Python
python从入门到精通(DAY 2)
2015/12/20 Python
python使用scrapy发送post请求的坑
2018/09/04 Python
使用python3实现操作串口详解
2019/01/01 Python
Python字典的核心底层原理讲解
2019/01/24 Python
pandas 数据索引与选取的实现方法
2019/06/21 Python
python爬取盘搜的有效链接实现代码
2019/07/20 Python
python实现kNN算法识别手写体数字的示例代码
2019/08/16 Python
pandas实现DataFrame显示最大行列,不省略显示实例
2019/12/26 Python
tensorflow没有output结点,存储成pb文件的例子
2020/01/04 Python
CSS3实现文字波浪线效果示例代码
2016/11/20 HTML / CSS
美国一家著名的儿童鞋制造商:Stride Rite
2017/01/02 全球购物
国际知名军事风格休闲装品牌:Alpha Industries(阿尔法工业)
2017/05/24 全球购物
豪华床上用品 :Jennifer Adams
2019/09/15 全球购物
给医务人员表扬信
2014/01/12 职场文书
幼教简历自我评价
2014/01/28 职场文书
财务会计专业自荐书
2014/06/30 职场文书
总经理岗位职责说明书
2014/07/30 职场文书
法人代表证明书范本
2015/06/18 职场文书
Go语言应该什么情况使用指针
2021/07/25 Golang