php示例詳解Constructor Prototype Pattern 原型模式
原型模式中主要角色
抽象原型(Prototype)角色:聲明一個(gè)克隆自己的接口
具體原型(Concrete Prototype)角色:實(shí)現(xiàn)一個(gè)克隆自己的操作
當(dāng)一個(gè)類大部分都是相同的只有部分是不同的時(shí)候,如果需要大量這個(gè)類的對(duì)象,每次都重復(fù)實(shí)例化那些相同的部分是開(kāi)銷很大的,而如果clone之前建立對(duì)象的那些相同的部分,就可以節(jié)約開(kāi)銷。
針對(duì)php的一種實(shí)現(xiàn)方式就是__construct()和initialize函數(shù)分開(kāi)分別處理這個(gè)類的初始化,construct里面放prototype也就是公共的部分,initialize里面是每個(gè)對(duì)象特殊的部分。這樣我們先建立一個(gè)類不initialize,以后每次clone這個(gè)類再進(jìn)行initialize就可以了。
在zend framework官方手冊(cè)里面提到了這個(gè)http://framework.zend.com/manual/2.0/en/user-guide/database-and-models.html,但是沒(méi)有細(xì)講,下面我來(lái)分析一下
一、引入
在zf2的model里面有一個(gè)albumTable類,相當(dāng)于一個(gè)操作數(shù)據(jù)庫(kù)動(dòng)作的助手類,里面用到了tablegateway。
為了每次初始化albumtable都是相同的一個(gè)類,將初始化工作放到了根目錄的module.php文件的getServiceConfig(),其中用到工廠模式,并且通過(guò)回調(diào)函數(shù),當(dāng)每次ServiceManager($sm)需要實(shí)例化一個(gè)對(duì)象的時(shí)候會(huì)自動(dòng)調(diào)用創(chuàng)建一個(gè)alumTable。下面代碼我們可以看出,創(chuàng)建一個(gè)albumTable還需要用相同的方式創(chuàng)建一個(gè)AlbumTableGateWay,這個(gè)類就用到了我們所要講的原型模式。
二、代碼詳解
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());//這個(gè)就是一個(gè)不變的原型 return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);//傳入到TableGateWay的構(gòu)造函數(shù)中去 }, ), ); }
注意并不是TableGateWay運(yùn)用了原型模式而是ResultSet這個(gè)類運(yùn)用了。每當(dāng)tablegateway調(diào)用select()或者insert()等方法的時(shí)候都會(huì)建立一個(gè)ResultSet用來(lái)表示結(jié)果,這些ResultSet中公共部分被clone,而獨(dú)特的部分類如data就會(huì)被initialize。
三、更多代碼示例
為了更清晰得了解這個(gè)原型,我們先拋開(kāi)zend這個(gè)大框架,看一個(gè)完整的代碼示例。示例來(lái)自
<a href=" Constructor Best Practices And The Prototype Pattern</a>
這篇文章關(guān)于prototype pattern的部分前半部分其實(shí)是混雜怎樣在構(gòu)造函數(shù)中運(yùn)用繼承來(lái)提高擴(kuò)展性,兩個(gè)模式看起來(lái)可能不太好理解,我們直接看最后的代碼關(guān)于prototype pattern的部分。
<?php //框架中很常見(jiàn)的adapter類,用來(lái)適配各種數(shù)據(jù)庫(kù),封裝一些基本數(shù)據(jù)庫(kù)連接操作。 //相當(dāng)于上面代碼中的adapter類 class DbAdapter { public function fetchAllFromTable($table) { return $arrayOfData; } } //運(yùn)用prototype pattern的類,注意construct和initialize是分開(kāi)的 //相當(dāng)于上面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() {} } //相當(dāng)于上面代碼中的TableGateway類,關(guān)于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; } }
這幾個(gè)類其實(shí)和上面zend代碼中的類是對(duì)應(yīng)的
Dbadapter -- adpater
RowGateWay -- ResultSet
UserRepository - TableGateWay
具體看代碼中的注釋。
這里的RowGateWay可以很明顯的看出在getusers中需要大量的實(shí)例化,那么原型模式就是很必要的了。
下面是運(yùn)用這個(gè)類的代碼
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
以上內(nèi)容是小編給大家介紹的php示例詳解Constructor Prototype Pattern 原型模式,希望大家喜歡。
相關(guān)文章
php分頁(yè)思路以及在Zend?Framework框架中的使用
php分頁(yè)思路以及在Zend?Framework框架中的使用,需要的朋友可以參考下2012-05-05CodeIgniter框架數(shù)據(jù)庫(kù)基本操作示例
這篇文章主要介紹了CodeIgniter框架數(shù)據(jù)庫(kù)基本操作,結(jié)合實(shí)例形式分析了CodeIgniter框架針對(duì)mysql數(shù)據(jù)庫(kù)的配置、用戶注冊(cè)、信息查詢、修改及刪除等基本操作技巧,需要的朋友可以參考下2018-05-05教你如何用php實(shí)現(xiàn)LOL數(shù)據(jù)遠(yuǎn)程獲取
LOL(英雄聯(lián)盟)最近非常的火爆,哥自然也在玩了,最近遇到個(gè)問(wèn)題,就是每次想看看自己的戰(zhàn)斗力啥的,還得先開(kāi)盒子等等,麻煩,最近有一個(gè)想法,打算把它實(shí)現(xiàn)出來(lái)。2014-06-06php面試中關(guān)于面向?qū)ο蟮南嚓P(guān)問(wèn)題
在本篇文章里小編整理了關(guān)于php面試中關(guān)于面向?qū)ο蟮南嚓P(guān)問(wèn)題內(nèi)容,以及相關(guān)回答,有需要的朋友們學(xué)習(xí)下。2019-02-02深入淺析php中sprintf與printf函數(shù)的用法及區(qū)別
這篇文章主要介紹了php中sprintf與printf函數(shù)的用法及區(qū)別,涉及到printf函數(shù)、sprintf函數(shù)相關(guān)資料,需要的朋友可以參考下2016-01-01php實(shí)現(xiàn)批量下載百度云盤文件例子分享
本文使用百度開(kāi)放云的PHP SDK實(shí)現(xiàn)批量下載百度云盤的文件,需要的朋友可以參考下。2014-04-04PHP反射使用實(shí)例和PHP反射API的中文說(shuō)明
這篇文章主要介紹了PHP反射使用實(shí)例和PHP反射API的中文說(shuō)明,重點(diǎn)在對(duì)PHP的反射API中每個(gè)方法都做了中文說(shuō)明,需要的朋友可以參考下2014-07-07destoon二次開(kāi)發(fā)模板及調(diào)用語(yǔ)法匯總
這篇文章主要介紹了destoon二次開(kāi)發(fā)模板及調(diào)用語(yǔ)法,需要的朋友可以參考下2014-06-06PHP動(dòng)態(tài)輸出JavaScript代碼實(shí)例
這篇文章主要介紹了PHP動(dòng)態(tài)輸出JS代碼實(shí)例,本文直接給出代碼實(shí)例,一看就懂,簡(jiǎn)潔明了,需要的朋友可以參考下2015-02-02