This time I will bring you a case analysis of PHP prototype mode. What are the precautions when using PHP prototype mode? The following is a practical case, let's take a look.
The Prototype Design Pattern is interesting because it uses a cloning technique to copy instantiated objects. New objects are created by copying prototype instances. Here, the instances are batch instances The purpose of the prototype design pattern is to reduce the overhead of instantiating objects by using clones. Instead of instantiating new objects from a class, you can use a clone of an existing instance.
Clone function
The key to using the prototyping pattern in PHP is to understand how to use the built-in functionclone()
.
<?php abstract class CloneObject { public $name; public $picture; abstract function clone(); } class Boy extends CloneObject { public function construct() { $this->face = "handsome"; $this->name = "chenqionghe"; } public function display() { echo 'look : '.$this->face;; echo '<br />'.$this->name.'<br />'; } public function clone() {} } $boy = new Boy(); $boy->display(); $cloneBoy = clone $boy; $cloneBoy->face = "still handsome"; $cloneBoy->display();
The running results are as follows
look : handsome
chenqionghe
look : still handsome
chenqionghe
$cloneBoy instance is cloned An instance of Boy, $boy, can access the same properties as $boy, and can change these properties like a direct instance of the Boy class.
Note: For cloned instances, clone keyword will instantiate another instance of the class for that instance (using the clone keyword can create a copy of the class, and if possible, the object's clone
method will be automatically called, but the object's ## cannot be called directly #clone method), regarding the process, one thing to note is that cloning will not start the action in the
constructor.
Simple Prototype example
Let’s take the study of fruit flies as an example. The goal of the research is to establish a prototype fruit fly, and then once a mutation occurs, build this mutant fruit flyAbstract class interface and concrete implementation
The two concrete class implementations of the prototype (IPrototype) respectively represent different genders of fruit flies, including gender variables (gender) and different genders and behavior.IPrototype.php
<?php abstract class IPrototype { public $eyeColor; public $winBeat; public $unitEypes; abstract function clone(); }
MaleProto.php
<?php include_once('IPrototype.php'); class MaleProto extends IPrototype { const gender = "MALE"; public $mated; public function construct() { $this->eyeColor = "red"; $this->winBeat = "220"; $this->unitEypes = "760"; } public function clone(){} }
FemaleProto.php
<?php include_once('IPrototype.php'); class FemaleProto extends IPrototype { const gender = "FEMAIL"; public $fecundity; public function construct() { $this->eyeColor = "red"; $this->winBeat = "220"; $this->unitEypes = "760"; } public function clone(){} }
customer
In the prototyping design pattern, the Client class is indeed an indispensable part. The reason is that although the concrete implementation of the subclass is used as the template for the instance, the specific work of cloning the instance using the same template is TheClient.php
<?php function autoload($class_name) { include_once $class_name.'.php'; } class Client { //用于直接实例化 private $fly1; private $fly2; //用于克隆 private $c1Fly; private $c2Fly; private $updatedCloneFly; public function construct() { //实例化 $this->fly1 = new MaleProto(); $this->fly2 = new FemaleProto(); //克隆 $this->c1Fly = clone $this->fly1; $this->c2Fly = clone $this->fly2; $this->updatedCloneFly = clone $this->fly2; //更新克隆 $this->c1Fly->mated = "true"; $this->c2Fly->fecundity = '186'; $this->updatedCloneFly->eyeColor = "purple"; $this->updatedCloneFly->winBeat = "220"; $this->updatedCloneFly->unitEyes = '750'; $this->updatedCloneFly->fecundity = '92'; //通过类型提示方法发送 $this->showFly($this->c1Fly); $this->showFly($this->c2Fly); $this->showFly($this->updatedCloneFly); } private function showFly(IPrototype $fly) { echo "Eye color: ".$fly->eyeColor."<br />"; echo "Wing Beats/second: ".$fly->winBeat."<br />"; echo "Eye units: ".$fly->unitEypes."<br />"; $genderNow = $fly::gender; echo "Gender: ".$genderNow."<br />"; if($genderNow == "FEMAIL") { echo "Number of eggs: ".$fly->fecundity."<hr />"; } else { echo "Mated: ".$fly->mated."<hr />"; } } } $worker = new Client();
Eye color: redPrototype mode depends on The customer uses the concrete prototype through the cloning process. In this design process, the customer is a participant who completes the cloning. Since cloning is a key element in prototype design, the customer is a basic participant, not just a requesting class.Wing Beats/second : 220
Eye units: 760
Gender: MALE
Mated: trueEye color: red
Wing Beats/second: 220
Eye units: 760
Gender: FEMAIL
Number of eggs: 186Eye color: purple
Wing Beats/second: 220
Eye units: 760
Gender: FEMAIL
Number of eggs: 92
Modern Enterprise Organization
In terms of creative design patterns, modern enterprise organizations are very suitable for prototype implementation. Nowadays, enterprise organizations often have complex and huge hierarchical structures, such as Like object-oriented programming, many common characteristics need to be modeled. Now describe a software engineering company through an example. A software engineering company is a typical modern organization. The Engineering Department is responsible for creating products, managing The Management department handles the coordination and organization of resources, and the Marketing department is responsible for the sales, promotion and overall marketing of products.Encapsulation in the interface
在这个原型实现中,首先为程序的接口(一个抽象类)增加OOP,与所有原型接口一样,这个接口包含一个克隆操作.另外它还包含一些抽象和具体的获取方法和设置方法.其中有一个抽象获取方法/设置方法对,但要由3个具体原型实现为这个抽象获取方法/设置方法对提供具体实现.其他获取方法和设置方法分分别应用于员工名,ID码和照片等属性.注意所有这些属性都是保护属性(protected),所以尽管具体的获取方法和设置方法有公共可见性,但由于操作中使用的属性具有保护和可见性,这就提供了某种程度的封装:
<?php abstract class IAcmePrototype { protected $name; protected $id; protected $employeePic; protected $department; //部门 abstract function setDept($orgCode); abstract function getDept(); //名字 public function setName($emName) { $this->name = $emName; } public function getName() { return $this->name; } //ID public function setId($emId) { $this->id = $emId; } public function getId() { return $this->id; } //雇员图像 public function setPic($ePic) { $this->employeePic = $ePic; } public function getPic() { return $this->employeePic; } abstract function clone(); }
利用这些获取方法和设置方法, 所有属性的值都通过继承的保护变量来设置.采用这种设计, 扩展类及其实例可以得到更好的封装.
接口实现
3个IAcmePrototype子类都必须实现"dept"抽象方法以及clone()
方法.类似地, 每个具体原型类还包含一个常量UNIT,它提供一个赋值,可以由实例(包括克隆的对象)作为标识
首先来看市场部的Marketing类:
Marketing.php
<?php include_once('IAcmePrototype.php'); class Marketing extends IAcmePrototype { const UNIT = "Marketing"; private $sales = "sales"; private $promotion = "promotion"; private $strategic = "strategic planning"; public function setDept($orgCode) { switch($orgCode) { case 101: $this->department = $this->sales; break; case 102: $this->department = $this->promotion; break; case 103: $this->department = $this->strategic; break; default : $this->department = "未识别的市场部"; } } public function getDept() { return $this->department; } public function clone() {} }
setDept()
方法的实现使用了一个参数.并不是直接输入市场部的部门,这个方法的参数是一个数字码, 通过一个switch语句,限制了3种可接受的情况和默认情况,别外两个原型实现也类似
Management.php
<?php include_once('IAcmePrototype.php'); class Management extends IAcmePrototype { const UNIT = "Management"; private $research = "research"; private $plan = "planning"; private $operations = "operations"; public function setDept($orgCode) { switch($orgCode) { case 201: $this->department = $this->research; break; case 202: $this->department = $this->plan; break; case 203: $this->department = $this->operations; break; default : $this->department = "未识别的管理部"; } } public function getDept() { return $this->department; } public function clone() {} }
Engineering.php
<?php include_once('IAcmePrototype.php'); class Engineering extends IAcmePrototype { const UNIT = "Engineering"; private $development = "development"; private $design = "design"; private $sysAd = "system administration"; public function setDept($orgCode) { switch($orgCode) { case 301: $this->department = $this->development; break; case 302: $this->department = $this->design; break; case 303: $this->department = $this->sysAd; break; default : $this->department = "未识别的工程部"; } } public function getDept() { return $this->department; } public function clone() {} }
以上这3个具体原型实现分别有其特定用途,不过它们都符合接口,可以创建各个原型实现的一个实例, 然后根据需要克隆多个实例.这个克隆的工作由Client类完成
客户
客户的设置非常简单: 分别创建各个具体原型的一个实例, 然后按以下列表来克隆各个实例:
市场部门实例:
-----市场部门克隆
-----市场部门克隆
管理部门实例
-----管理部门克隆
工程部门实例
-----工程部门克隆
-----工程部门克隆
将来只使用这些克隆对象.使用获取方法和设置方法将各个特定情况的信息赋给这些克隆对象.以下是Client的实现
Client.php
<?php function autoload($class_name) { include_once $class_name.'.php'; } class Client { private $market; private $manage; private $engineer; public function construct() { $this->makeConProto(); $Tess = clone $this->market; $this->setEmployee($Tess, "Tess Smith" , 101, 'ts101-1234', 'tess.png'); $this->showEmployee($Tess); $Jacob = clone $this->market; $this->setEmployee($Jacob, "Jacob Jones" , 101, 'jj101-2234', 'jacob.png'); $this->showEmployee($Jacob); $Ricky = clone $this->manage; $this->setEmployee($Ricky, "Ricky Rodriguez" , 203, 'rr101-5634', 'ricky.png'); $this->showEmployee($Ricky); $Olivaia = clone $this->engineer; $this->setEmployee($Olivaia, "Olivaia Perez" , 302, 'op301-1278', 'olivia.png'); $this->showEmployee($Olivaia); $John = clone $this->engineer; $this->setEmployee($John, "John Jacson" , 101, 'jj301-14548', 'john.png'); $this->showEmployee($John); } private function makeConProto() { $this->market = new Marketing(); $this->manage = new Management(); $this->engineer = new Engineering(); } private function showEmployee(IAcmePrototype $employeeNow) { $px = $employeeNow->getPic(); echo "<img src=$px width='150' height='150' /><br />"; echo $employeeNow->getName().'<br />'; echo $employeeNow->getDept().':'.$employeeNow::UNIT.'<br />'; echo $employeeNow->getId().'<hr />'; } private function setEmployee(IAcmePrototype $employeeNow, $nm, $dp, $id, $px) { $employeeNow->setName($nm); $employeeNow->setDept($dp); $employeeNow->setId($id); $employeeNow->setPic($px); } } $worker = new Client();
解释:
客户Client的构造函数类包含3个私有属性, 用来分别实例化3个具体原型类. makeConPro()
方法生成必要的实例.
接下来,使用克隆技术创建一个"员工"实例.然后,这个实例向一个设置方法setEmployee()发送特定的实例信息,这个设置方法使用IAcmePrototype接口类型提示,不过需要说明, 它只对第一个参数使用类型提示,其他参数都没有类型提示, 并不要求它们派生自IAcmePrototype接口.克隆"员工"可以使用IAcmePrototype抽象类的所有设置方法以及具体原型类实现的setDept()方法.
要使用各个员工的数据,Client类可以使用继承的获取方法.以下是运行Client输出的结果
Tess Smith
sales:Marketing
ts101-1234
Jacob Jones
sales:Marketing
jj101-2234
Ricky Rodriguez
operations:Management
rr101-5634
Olivaia Perez
design:Engineering
op301-1278
John Jacson
未识别的工程部:Engineering
jj301-14548
可以根据需要增加更多的克隆, 而且只需要对具体原型类完成一次实例化.使用原型模式时, 并不是建立具体类的多个实例,而只需要一个类实例化和多个克隆.
完成修改,增加特性
要记住,最重要(可能也是最基本)的是, 设计模式允许开发人员修改和增补程序,而不必一切从头开始.例如, 假设总裁决定公司增加一个新的部门,比如研究部门(Research), 这会很难吗?一点也不难.Research可以扩展IAcmePrototype抽象类, 然后实现抽象获取方法和设置方法来反映这个研究部门的组织.需要说明,Client类中获取方法和设置方法使用的代码提示指示一个接口,而不是一个抽象类的具体实现.所以, 只要增加的单元正确地实现了这个接口,就能顺利地增加到应用中, 而不会带来波动,也不需要对程序中的其他参与者进行重构.
Not only can more concrete classes be added, but individual classes can be easily modified without causing disruption. For example, suppose the marketing department of this organization decides that, in addition to their existing departments, they need a special The online marketing department. As a result, the switch/case operation requires a new branch (case) and a new private attribute (variable) to describe the new department. This change will be frozen in a separate class , without affecting other participants. Since this change will not cause damage, the larger the scale of the application, the more important this is. It can be seen that the prototyping design pattern not only supports consistency, but also supports flexible changes.
Prototypes in the PHP world
Since PHP is a server-side language and an important tool for interacting with MySQL database, prototyping is Patterns are particularly useful here. Instead of creating separate objects for the first element in the database, PHP can use the Prototype pattern to create an instance of a concrete class and then clone the remaining instances (records) using the data in the database.
Understand After the cloning process, compared to the process of direct instantiation, you may ask: "What is the difference?" In other words, why does cloning require fewer resources than directly instantiating the object? The difference is not directly visible. When an object is instanced through cloning, it does not start a constructor. The clone gets all the properties of the original class, even those of the parent interface, and also inherits all the values passed to the instantiated object. All values generated by the constructor and the values stored in the object properties will become part of the cloned object. Therefore, there is no return constructor. If you find that your cloned object really needs to access the values generated by the constructor but cannot access them, this indicates that the class needs to be refactored so that Instances can have all the information they need, and can pass this data to cloned objects.
In general, the prototype pattern is very suitable for many different types of PHP projects. If solving a problem requires even Both the creational mode and the prototype mode can be used.
I believe you have mastered the method after reading the case in this article. For more exciting information, please pay attention to other related articles on the PHP Chinese website!
Recommended reading:
PHP Closure Principle (OCP) use case analysis
Detailed explanation of PHP dependency inversion case
The above is the detailed content of PHP prototype pattern case analysis. For more information, please follow other related articles on the PHP Chinese website!