搜索
首页后端开发php教程Constructor Prototype Pattern 原型模式(PHP示范)

Constructor Prototype Pattern 原型模式(PHP示例)

当一个类大部分都是相同的只有部分是不同的时候,如果需要大量这个类的对象,每次都重复实例化那些相同的部分是开销很大的,而如果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,这个类就用到了我们所要讲的原型模式。

二、代码详解

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

注意并不是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的部分。

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

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

Dbadapter -- adpater

RowGateWay -- ResultSet

UserRepository - TableGateWay

具体看代码中的注释。

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

下面是运用这个类的代码

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

 

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
优化PHP代码:减少内存使用和执行时间优化PHP代码:减少内存使用和执行时间May 10, 2025 am 12:04 AM

TOOPTIMIZEPHPCODEFORDUSEMEMORYUSAGEAGEAGEAGEAGEAGEANDEXECUTITIEM,关注台词:1)USEREEREFERESCENCENCINCOPYINSTEADOFCOPYINGINATATASTRUCTURESTROUCTURESTOREDUCEMORYCONSUMPTION.2)杠杆phphppphpphp'sbuilt intimpunctionslikearray_mapforfunctionslikearray_mapforfforfforfforfasterapasterexecution.3)

PHP电子邮件:分步发送指南PHP电子邮件:分步发送指南May 09, 2025 am 12:14 AM

phpisusedforsendendemailsduetoitsignegrationwithservermailservicesand andexternalsmtpproviders,自动化notifications andMarketingCampaigns.1)设置设置yourphpenvironcormentswironmentswithaweberswithawebserverserverserverandphp,确保themailfunctionisenabled.2)useabasicscruct

如何通过PHP发送电子邮件:示例和代码如何通过PHP发送电子邮件:示例和代码May 09, 2025 am 12:13 AM

发送电子邮件的最佳方法是使用PHPMailer库。1)使用mail()函数简单但不可靠,可能导致邮件进入垃圾邮件或无法送达。2)PHPMailer提供更好的控制和可靠性,支持HTML邮件、附件和SMTP认证。3)确保正确配置SMTP设置并使用加密(如STARTTLS或SSL/TLS)以增强安全性。4)对于大量邮件,考虑使用邮件队列系统来优化性能。

高级PHP电子邮件:自定义标题和功能高级PHP电子邮件:自定义标题和功能May 09, 2025 am 12:13 AM

CustomHeadersheadersandAdvancedFeaturesInphpeMailenHanceFunctionalityAndreliability.1)CustomHeadersheadersheadersaddmetadatatatatataatafortrackingandCategorization.2)htmlemailsallowformattingandttinganditive.3)attachmentscanmentscanmentscanbesmentscanbestmentscanbesentscanbesentingslibrarieslibrarieslibrariesliblarikelikephpmailer.4)smtppapapairatienticationaltication enterticationallimpr

使用PHP和SMTP发送电子邮件的指南使用PHP和SMTP发送电子邮件的指南May 09, 2025 am 12:06 AM

使用PHP和SMTP发送邮件可以通过PHPMailer库实现。1)安装并配置PHPMailer,2)设置SMTP服务器细节,3)定义邮件内容,4)发送邮件并处理错误。使用此方法可以确保邮件的可靠性和安全性。

使用PHP发送电子邮件的最佳方法是什么?使用PHP发送电子邮件的最佳方法是什么?May 08, 2025 am 12:21 AM

ThebestapproachforsendingemailsinPHPisusingthePHPMailerlibraryduetoitsreliability,featurerichness,andeaseofuse.PHPMailersupportsSMTP,providesdetailederrorhandling,allowssendingHTMLandplaintextemails,supportsattachments,andenhancessecurity.Foroptimalu

PHP中依赖注入的最佳实践PHP中依赖注入的最佳实践May 08, 2025 am 12:21 AM

使用依赖注入(DI)的原因是它促进了代码的松耦合、可测试性和可维护性。1)使用构造函数注入依赖,2)避免使用服务定位器,3)利用依赖注入容器管理依赖,4)通过注入依赖提高测试性,5)避免过度注入依赖,6)考虑DI对性能的影响。

PHP性能调整技巧和技巧PHP性能调整技巧和技巧May 08, 2025 am 12:20 AM

phperformancetuningiscialbecapeitenhancesspeedandeffice,whatevitalforwebapplications.1)cachingwithapcureduccureducesdatabaseloadprovesrovesponsemetimes.2)优化

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器

Dreamweaver Mac版

Dreamweaver Mac版

视觉化网页开发工具

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具