Main characters in prototype mode
Abstract Prototype role: declare an interface that clons itself
Concrete Prototype role: implement a cloning operation
When most of a class is the same and only the parts are different, if a large number of objects of this class are needed, it is expensive to instantiate the same parts each time, and if the same parts of the object were created before clone, it can save overhead.
One way to implement php is to process the initialization of this class separately by __construct() and initialize functions. The prototype is the public part in construct, and the special part of each object is placed in initialize. In this way, we first create a class that does not initialize, and then initialize this class in the future.
This is mentioned in the official zend framework manual/manual/2.0/en/user-guide/, but I haven't explained it in detail. Let me analyze it below
1. Introduction
There is an albumTable class in the model of zf2, which is equivalent to an assistant class for operating database actions, and tablegateway is used.
In order to initialize the albumtable each time, the initialization work is placed in the getServiceConfig() of the root file, which uses the factory mode. Through the callback function, when each ServiceManager ($sm) needs to instantiate an object, it will automatically call to create an alumTable. We can see from the following code that creating an albumTable requires creating an AlbumTableGateWay in the same way, and this class uses the prototype pattern we want to talk about.
2. Detailed explanation of the code
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());//This is an unchanging prototype return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);//Passed into the TableGateWay constructor }, ), ); }
Note that TableGateWay does not use the prototype mode but the ResultSet class. Whenever the tablegateway calls select() or insert() methods, a ResultSet will be established to represent the result. The public parts of these ResultSets are clone, and unique parts such as data will be initialized.
3. More code examples
In order to understand this prototype more clearly, let’s put aside the big framework of zend and look at a complete code example. Example from
<a href="/2012/03/09/php-constructor-best-practices-and-the-prototype-pattern">PHP Constructor Best Practices And The Prototype Pattern</a>
The first half of this article about prototype pattern is actually mixed. How to use inheritance in the constructor to improve scalability. The two patterns may not seem easy to understand. Let's look directly at the last code about prototype pattern.
<?php //The adapter class is a very common framework, used to adapt to various databases and encapsulate some basic database connection operations.//Equivalent to the adapter class in the above codeclass DbAdapter { public function fetchAllFromTable($table) { return $arrayOfData; } } //Use the prototype pattern class, note that construct and initialize are separated//Equivalent to the ResultSet class in the above zend codeclass 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() {} } //Equivalent to the TableGateway class in the above code. You can learn more about 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; } }
These classes are actually corresponding to the classes in the zend code above.
Dbadapter -- adpater
RowGateWay -- ResultSet
UserRepository - TableGateWay
Depending on the comments in the code, please see.
RowGateWay here can be clearly seen that a large number of instantiation is required in getusers, so the prototype pattern is very necessary.
Here is the code that uses this class
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
The above content is a detailed explanation of the php examples introduced by the editor to you. I hope you like it.