原型模式中主要角色
抽象原型(Prototype)角色:聲明一個克隆自己的接口
具體原型(Concrete Prototype)角色:實現(xiàn)一個克隆自己的操作
當(dāng)一個類大部分都是相同的只有部分是不同的時候,如果需要大量這個類的對象,每次都重復(fù)實例化那些相同的部分是開銷很大的,而如果clone之前建立對象的那些相同的部分,就可以節(jié)約開銷。
針對php的一種實現(xiàn)方式就是__construct()和initialize函數(shù)分開分別處理這個類的初始化,construct里面放prototype也就是公共的部分,initialize里面是每個對象特殊的部分。這樣我們先建立一個類不initialize,以后每次clone這個類再進(jìn)行initialize就可以了。
在zend framework官方手冊里面提到了這個http://framework.zend.com/manual/2.0/en/user-guide/database-and-models.html,但是沒有細(xì)講,下面我來分析一下
一、引入
在zf2的model里面有一個albumTable類,相當(dāng)于一個操作數(shù)據(jù)庫動作的助手類,里面用到了tablegateway。
為了每次初始化albumtable都是相同的一個類,將初始化工作放到了根目錄的module.php文件的getServiceConfig(),其中用到工廠模式,并且通過回調(diào)函數(shù),當(dāng)每次ServiceManager($sm)需要實例化一個對象的時候會自動調(diào)用創(chuàng)建一個alumTable。下面代碼我們可以看出,創(chuàng)建一個albumTable還需要用相同的方式創(chuàng)建一個AlbumTableGateWay,這個類就用到了我們所要講的原型模式。
二、代碼詳解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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的構(gòu)造函數(shù)中去 }, ), ); } |
注意并不是TableGateWay運用了原型模式而是ResultSet這個類運用了。每當(dāng)tablegateway調(diào)用select()或者insert()等方法的時候都會建立一個ResultSet用來表示結(jié)果,這些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>
這篇文章關(guān)于prototype pattern的部分前半部分其實是混雜怎樣在構(gòu)造函數(shù)中運用繼承來提高擴展性,兩個模式看起來可能不太好理解,我們直接看最后的代碼關(guān)于prototype pattern的部分。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
<?php //框架中很常見的adapter類,用來適配各種數(shù)據(jù)庫,封裝一些基本數(shù)據(jù)庫連接操作。 //相當(dāng)于上面代碼中的adapter類 class DbAdapter { public function fetchAllFromTable( $table ) { return $arrayOfData ; } } //運用prototype pattern的類,注意construct和initialize是分開的 //相當(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 ; } } |
這幾個類其實和上面zend代碼中的類是對應(yīng)的
Dbadapter -- adpater
RowGateWay -- ResultSet
UserRepository - TableGateWay
具體看代碼中的注釋。
這里的RowGateWay可以很明顯的看出在getusers中需要大量的實例化,那么原型模式就是很必要的了。
下面是運用這個類的代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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 原型模式,希望大家喜歡。