• 售前

  • 售后

热门帖子
入门百科

PHP设计模式之原型模式界说与用法详解

[复制链接]
123457021 显示全部楼层 发表于 2021-10-25 19:07:19 |阅读模式 打印 上一主题 下一主题
本文实例报告了PHP操持模式之原型模式界说与用法。分享给各人供各人参考,详细如下:
原型操持模式(Prototype Design Pattern)很故意思, 因为它利用了一种克隆技能来复制实例化的对象. 新对象是通过复制原型实例来创建的. 在这里, 实例是批实例化的详细类.原型操持模式的目的是通过利用克隆来淘汰实例化对象的开销.与其从一个类实例化新对象, 完全可以利用一个已有实例的克隆.
克隆函数
PHP中利用原型操持模式的关键是要了解怎样利用内置函数
  1. __clone()
复制代码
.
  1. <?php
  2. abstract class CloneObject
  3. {
  4.   public $name;
  5.   public $picture;
  6.   abstract function __clone();
  7. }
  8. class Boy extends CloneObject
  9. {
  10.   public function __construct()
  11.   {
  12.     $this->face = "handsome";
  13.     $this->name = "chenqionghe";
  14.   }
  15.   public function display()
  16.   {
  17.     echo 'look : '.$this->face;;
  18.     echo '<br />'.$this->name.'<br />';
  19.   }
  20.   public function __clone() {}
  21. }
  22. $boy = new Boy();
  23. $boy->display();
  24. $cloneBoy = clone $boy;
  25. $cloneBoy->face = "still handsome";
  26. $cloneBoy->display();
复制代码
运行结果如下
  1. look : handsome
  2. chenqionghe
  3. look : still handsome
  4. chenqionghe
复制代码
$cloneBoy实例是通过克隆Boy的实例$boy, 它可以像$boy一样访问相同的属性, 而且像Boy类的直接实例一样改变这些属性.
注意: 对于所克隆的实例 , clone关键字会为该实例的类实例化另一个实例(利用克隆关键字可以创建一个类的副本, 假如大概, 会主动调用对象的
  1. __clone
复制代码
方法, 但不能直接调用 对象的
  1. __clone
复制代码
方法), 关于过程, 有一点须要注意的是, 克隆不会不会启动构造函数中的动作.
简单的原型例子
我们以研究果蝇为例.研究的目标是建立一个原型果蝇, 然后一旦出现变异, 就构建这个变异果蝇
抽象类接口和详细实现
原型(IPrototype)的两个详细类实现分别表现差别性别的果蝇, 包罗性别变量(gender)和差别性别的和行为.
IPrototype.php
  1. <?php
  2. abstract class IPrototype
  3. {
  4.   public $eyeColor;
  5.   public $winBeat;
  6.   public $unitEypes;
  7.   abstract function __clone();
  8. }
复制代码
IPrototype的这两个实现的区别体现在性别上, 性别用常量标识, 一个是MALE,另一个是FEMAIL.雄果蝇有一个$mated布尔变量, 雄果蝇交配后,这个布尔变量会设置为true, 雌果蝇有一个$fecundity变量,此中包含一个数字值, 表现这只雄果蝇的繁殖本领(产卵个数):
MaleProto.php
  1. <?php
  2. include_once('IPrototype.php');
  3. class MaleProto extends IPrototype
  4. {
  5.   const gender = "MALE";
  6.   public $mated;
  7.   public function __construct()
  8.   {
  9.     $this->eyeColor = "red";
  10.     $this->winBeat = "220";
  11.     $this->unitEypes = "760";
  12.   }
  13.   public function __clone(){}
  14. }
复制代码
FemaleProto.php
  1. <?php
  2. include_once('IPrototype.php');
  3. class FemaleProto extends IPrototype
  4. {
  5.   const gender = "FEMAIL";
  6.   public $fecundity;
  7.   public function __construct()
  8.   {
  9.     $this->eyeColor = "red";
  10.     $this->winBeat = "220";
  11.     $this->unitEypes = "760";
  12.   }
  13.   public function __clone(){}
  14. }
复制代码
客户
在原型操持模式中,Clien类确实是一个不可缺少的部分.缘故原由在于, 尽管要将子类详细实现作为实例的模板,但利用相同的模板克隆实例的详细工作是由Client类完成的
Client.php
  1. <?php
  2. function __autoload($class_name)
  3. {
  4.   include_once $class_name.'.php';
  5. }
  6. class Client
  7. {
  8.   //用于直接实例化
  9.   private $fly1;
  10.   private $fly2;
  11.   //用于克隆
  12.   private $c1Fly;
  13.   private $c2Fly;
  14.   private $updatedCloneFly;
  15.   public function __construct()
  16.   {
  17.     //实例化
  18.     $this->fly1 = new MaleProto();
  19.     $this->fly2 = new FemaleProto();
  20.     //克隆
  21.     $this->c1Fly = clone $this->fly1;
  22.     $this->c2Fly = clone $this->fly2;
  23.     $this->updatedCloneFly = clone $this->fly2;
  24.     //更新克隆
  25.     $this->c1Fly->mated = "true";
  26.     $this->c2Fly->fecundity = '186';
  27.     $this->updatedCloneFly->eyeColor = "purple";
  28.     $this->updatedCloneFly->winBeat = "220";
  29.     $this->updatedCloneFly->unitEyes = '750';
  30.     $this->updatedCloneFly->fecundity = '92';
  31.     //通过类型提示方法发送
  32.     $this->showFly($this->c1Fly);
  33.     $this->showFly($this->c2Fly);
  34.     $this->showFly($this->updatedCloneFly);
  35.   }
  36.   private function showFly(IPrototype $fly)
  37.   {
  38.     echo "Eye color: ".$fly->eyeColor."<br />";
  39.     echo "Wing Beats/second: ".$fly->winBeat."<br />";
  40.     echo "Eye units: ".$fly->unitEypes."<br />";
  41.     $genderNow = $fly::gender;
  42.     echo "Gender: ".$genderNow."<br />";
  43.     if($genderNow == "FEMAIL")
  44.     {
  45.       echo "Number of eggs: ".$fly->fecundity."<hr />";
  46.     }
  47.     else
  48.     {
  49.       echo "Mated: ".$fly->mated."<hr />";
  50.     }
  51.   }
  52. }
  53. $worker = new Client();
复制代码
运行结果如下
  1. Eye color: red
  2. Wing Beats/second: 220
  3. Eye units: 760
  4. Gender: MALE
  5. Mated: trueEye color: red
  6. Wing Beats/second: 220
  7. Eye units: 760
  8. Gender: FEMAIL
  9. Number of eggs: 186Eye color: purple
  10. Wing Beats/second: 220
  11. Eye units: 760
  12. Gender: FEMAIL
  13. Number of eggs: 92
复制代码
原型模式要依靠客户通过 不念克隆过程利用详细原型.在这个操持过程中, 客户是完成克隆的参与者, 由于克隆是原型操持中的关键要素, 以是客户是一个根本参与者, 而不但仅是一个请求类.
现代企业构造
在创建型操持模式方面,现代企业构造就非常适合原型实现.现在企业构造往往是复杂而庞大的层次布局, 像面向对象编程一样,要为许多共同的特性建模.现在通过一个例子形貌软件工程公司.
软件工程公司是一个典型的现代构造.工程部(Engineering Department)负责创建产物,管理部(Management)处理资源的和谐构造,市场部(Marketing)负责产物的贩卖,推广和团体营销.
接口中的封装
在这个原型实现中,起首为步伐的接口(一个抽象类)增长OOP,与全部原型接口一样,这个接口包含一个克隆操作.别的它还包含一些抽象和详细的获取方法和设置方法.此中有一个抽象获取方法/设置方法对,但要由3个详细原型实现为这个抽象获取方法/设置方法对提供详细实现.其他获取方法和设置方法分分别应用于员工名,ID码和照片等属性.注意全部这些属性都是掩护属性(protected),以是尽管详细的获取方法和设置方法有公共可见性,但由于操作中利用的属性具有掩护和可见性,这就提供了某种程度的封装:
  1. <?php
  2. abstract class IAcmePrototype
  3. {
  4.   protected $name;
  5.   protected $id;
  6.   protected $employeePic;
  7.   protected $department;
  8.   //部门
  9.   abstract function setDept($orgCode);
  10.   abstract function getDept();
  11.   //名字
  12.   public function setName($emName)
  13.   {
  14.     $this->name = $emName;
  15.   }
  16.   public function getName()
  17.   {
  18.     return $this->name;
  19.   }
  20.   //ID
  21.   public function setId($emId)
  22.   {
  23.     $this->id = $emId;
  24.   }
  25.   public function getId()
  26.   {
  27.     return $this->id;
  28.   }
  29.   //雇员图像
  30.   public function setPic($ePic)
  31.   {
  32.     $this->employeePic = $ePic;
  33.   }
  34.   public function getPic()
  35.   {
  36.     return $this->employeePic;
  37.   }
  38.   abstract function __clone();
  39. }
复制代码
利用这些获取方法和设置方法, 全部属性的值都通过继承的掩护变量来设置.接纳这种操持, 扩展类及其实例可以得到更好的封装.
接口实现
3个IAcmePrototype子类都必须实现"dept"抽象方法以及
  1. __clone()
复制代码
方法.雷同地, 每个详细原型类还包含一个常量UNIT,它提供一个赋值,可以由实例(包罗克隆的对象)作为标识
起首来看市场部的Marketing类:
Marketing.php
  1. <?php
  2. include_once('IAcmePrototype.php');
  3. class Marketing extends IAcmePrototype
  4. {
  5.   const UNIT = "Marketing";
  6.   private $sales = "sales";
  7.   private $promotion = "promotion";
  8.   private $strategic = "strategic planning";
  9.   public function setDept($orgCode)
  10.   {
  11.     switch($orgCode)
  12.     {
  13.       case 101:
  14.         $this->department = $this->sales;
  15.         break;
  16.       case 102:
  17.         $this->department = $this->promotion;
  18.         break;
  19.       case 103:
  20.         $this->department = $this->strategic;
  21.         break;
  22.       default :
  23.         $this->department = "未识别的市场部";
  24.     }
  25.   }
  26.   public function getDept()
  27.   {
  28.     return $this->department;
  29.   }
  30.   public function __clone() {}
  31. }
复制代码
  1. setDept()
复制代码
方法的实现利用了一个参数.并不是直接输入市场部的部门,这个方法的参数是一个数字码, 通过一个switch语句,限定了3种可担当的情况和默认情况,别外两个原型实现也雷同
Management.php
  1. <?php
  2. include_once('IAcmePrototype.php');
  3. class Management extends IAcmePrototype
  4. {
  5.   const UNIT = "Management";
  6.   private $research = "research";
  7.   private $plan = "planning";
  8.   private $operations = "operations";
  9.   public function setDept($orgCode)
  10.   {
  11.     switch($orgCode)
  12.     {
  13.       case 201:
  14.         $this->department = $this->research;
  15.         break;
  16.       case 202:
  17.         $this->department = $this->plan;
  18.         break;
  19.       case 203:
  20.         $this->department = $this->operations;
  21.         break;
  22.       default :
  23.         $this->department = "未识别的管理部";
  24.     }
  25.   }
  26.   public function getDept()
  27.   {
  28.     return $this->department;
  29.   }
  30.   public function __clone() {}
  31. }
复制代码
Engineering.php
  1. <?php
  2. include_once('IAcmePrototype.php');
  3. class Engineering extends IAcmePrototype
  4. {
  5.   const UNIT = "Engineering";
  6.   private $development = "development";
  7.   private $design = "design";
  8.   private $sysAd = "system administration";
  9.   public function setDept($orgCode)
  10.   {
  11.     switch($orgCode)
  12.     {
  13.       case 301:
  14.         $this->department = $this->development;
  15.         break;
  16.       case 302:
  17.         $this->department = $this->design;
  18.         break;
  19.       case 303:
  20.         $this->department = $this->sysAd;
  21.         break;
  22.       default :
  23.         $this->department = "未识别的工程部";
  24.     }
  25.   }
  26.   public function getDept()
  27.   {
  28.     return $this->department;
  29.   }
  30.   public function __clone() {}
  31. }
复制代码
以上这3个详细原型实现分别有其特定用途,不外它们都符合接口,可以创建各个原型实现的一个实例, 然后根据须要克隆多个实例.这个克隆的工作由Client类完成
客户
客户的设置非常简单: 分别创建各个详细原型的一个实例, 然后按以下列表来克隆各个实例:
市场部门实例:
-----市场部门克隆
-----市场部门克隆
管理部门实例
-----管理部门克隆
工程部门实例
-----工程部门克隆
-----工程部门克隆
将来只利用这些克隆对象.利用获取方法和设置方法将各个特定情况的信息赋给这些克隆对象.以下是Client的实现
Client.php
  1. <?php
  2. function __autoload($class_name)
  3. {
  4.   include_once $class_name.'.php';
  5. }
  6. class Client
  7. {
  8.   private $market;
  9.   private $manage;
  10.   private $engineer;
  11.   public function __construct()
  12.   {
  13.     $this->makeConProto();
  14.     $Tess = clone $this->market;
  15.     $this->setEmployee($Tess, "Tess Smith" , 101, 'ts101-1234', 'tess.png');
  16.     $this->showEmployee($Tess);
  17.     $Jacob = clone $this->market;
  18.     $this->setEmployee($Jacob, "Jacob Jones" , 101, 'jj101-2234', 'jacob.png');
  19.     $this->showEmployee($Jacob);
  20.     $Ricky = clone $this->manage;
  21.     $this->setEmployee($Ricky, "Ricky Rodriguez" , 203, 'rr101-5634', 'ricky.png');
  22.     $this->showEmployee($Ricky);
  23.     $Olivaia = clone $this->engineer;
  24.     $this->setEmployee($Olivaia, "Olivaia Perez" , 302, 'op301-1278', 'olivia.png');
  25.     $this->showEmployee($Olivaia);
  26.     $John = clone $this->engineer;
  27.     $this->setEmployee($John, "John Jacson" , 101, 'jj301-14548', 'john.png');
  28.     $this->showEmployee($John);
  29.   }
  30.   private function makeConProto()
  31.   {
  32.     $this->market = new Marketing();
  33.     $this->manage = new Management();
  34.     $this->engineer = new Engineering();
  35.   }
  36.   private function showEmployee(IAcmePrototype $employeeNow)
  37.   {
  38.     $px = $employeeNow->getPic();
  39.     echo "<img src=$px width='150' height='150' /><br />";
  40.     echo $employeeNow->getName().'<br />';
  41.     echo $employeeNow->getDept().':'.$employeeNow::UNIT.'<br />';
  42.     echo $employeeNow->getId().'<hr />';
  43.   }
  44.   private function setEmployee(IAcmePrototype $employeeNow, $nm, $dp, $id, $px)
  45.   {
  46.     $employeeNow->setName($nm);
  47.     $employeeNow->setDept($dp);
  48.     $employeeNow->setId($id);
  49.     $employeeNow->setPic($px);
  50.   }
  51. }
  52. $worker = new Client();
复制代码
表明:
客户Client的构造函数类包含3个私有属性, 用来分别实例化3个详细原型类.
  1. makeConPro()
复制代码
方法天生须要的实例.
接下来,利用克隆技能创建一个"员工"实例.然后,这个实例向一个设置方法setEmployee()发送特定的实例信息,这个设置方法利用IAcmePrototype接口范例提示,不外须要说明, 它只对第一个参数利用范例提示,其他参数都没有范例提示, 并不要求它们派生自IAcmePrototype接口.克隆"员工"可以利用IAcmePrototype抽象类的全部设置方法以及详细原型类实现的setDept()方法.
要利用各个员工的数据,Client类可以利用继承的获取方法.以下是运行Client输出的结果
  1. Tess Smith
  2. sales:Marketing
  3. ts101-1234
  4. Jacob Jones
  5. sales:Marketing
  6. jj101-2234
  7. Ricky Rodriguez
  8. operations:Management
  9. rr101-5634
  10. Olivaia Perez
  11. design:Engineering
  12. op301-1278
  13. John Jacson
  14. 未识别的工程部:Engineering
  15. jj301-14548
复制代码
可以根据须要增长更多的克隆, 而且只须要对详细原型类完成一次实例化.利用原型模式时, 并不是建立详细类的多个实例,而只须要一个类实例化和多个克隆.
完成修改,增长特性
要记住,最重要(大概也是最根本)的是, 操持模式答应开辟人员修改和增补步伐,而不必一切重新开始.例如, 假设总裁决定公司增长一个新的部门,比如研究部门(Research), 这会很难吗?一点也不难.Research可以扩展IAcmePrototype抽象类, 然后实现抽象获取方法和设置方法来反映这个研究部门的构造.须要说明,Client类中获取方法和设置方法利用的代码提示指示一个接口,而不是一个抽象类的详细实现.以是, 只要增长的单位正确地实现了这个接口,就能顺利地增长到应用中, 而不会带来波动,也不须要对步伐中的其他参与者举行重构.
不但可以增长更多的详细类, 还可以很容易地对各个类举行修改, 而不会造成破坏.例如假设这个构造的市场部决定,除了现有的部门外, 他们还须要一个特别的在线市场部,. 如许一来, switch/case操作须要一个新的分支(case), 还要有一个新的私有属性(变量)来形貌新增的这个部门.这个改变将封冻在单独的类中, 而不会影响其他参与者.由于这种改变不会带来破坏, 以是应用的规模越大, 这一点就越重要.可以看到原型操持模式不但支持一致性, 还支持灵活的改变.
PHP天下中的原型
由于PHP是一个服务器端语言,也是与MySQL数据库交互的一个重要工具,以是原型操持模式尤其实用 .并不是为数据库的第一个元素分别创建对象,PHP可以利用原型模式创建详细类的一个实例,然后利用数据库中的数据克隆其余的实例(记载).
了解克隆过程之后,与直接实例化的过程相比,你大概会问:"这有什么区别?" 换句话说,为什么克隆比直接实例化对象须要的资源少?它们的区别并不能直接看到. 一个对象通过克隆创建实例时, 它不会启动构造函数.克隆能得到原始类的全部属性, 乃至还包含父接口的属性,别的还继承了通报实例化对象的全部值.构造函数天生的全部值以及存储在对象属性中的值都会成为克隆对象的一部分.以是没有返回构造函数.假如发现你的克隆对象确实须要访问构造函数天生的值但又无法访问, 这说明须要对类举行重构,使实例能拥有它们须要的一切信息, 而且可以把这些数据通报给克隆对象.
总的来说, 原型模式在许多差别范例的PHP项目中都很实用, 假如办理一个问题须要乃至创建型模式, 都可以利用原型模式.
更多关于PHP相干内容感爱好的读者可检察本站专题:《php面向对象步伐操持入门教程》、《PHP根本语法入门教程》、《PHP数组(Array)操作本领大全》、《php字符串(string)用法总结》、《php+mysql数据库操作入门教程》及《php常见数据库操作本领汇总》
希望本文所述对各人PHP步伐操持有所资助。

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作