原型设计模式
Notice:
PHP中,原型设计模式的关键是要了解如何使用内置函数__clone()
抽象原型角色(Prototype):声明一个克隆自身的接口
具体原型角色(ConcretePrototype):实现一个克隆自身的操作
原型设计模式的目的: 通过克隆以减少实例化对象的开销,与其实例化新对象,完全可以使用一个已有实例的克隆
注意Client类是原型设计模式中不可缺少的一部分
模型:
何时使用原型设计模式
如果一个项目要求你创建某个原型对象的多个实例,就可以使用原型设计模式
原型模式还可以用来创建一种组织结构,可以根据实际的组织来创建和填充其中的位置
克隆与构造函数
克隆不会启动构造函数中的动作,但是可以进行赋值之类的操作,比如
$this->act = 'action'
这样的操作会被执行,但是如果要'print $this->act',那么这个打印的动作将不会被执行这就意味着原型设计模式不能依赖于构造函数提供重要的输出或返回结果
构造函数不要做具体的工作,如果一个类实例化要完成大量初始化,结果往往不灵活,而且这是过渡耦合的设计
并不是说构造函数不能根据需要赋值,而是它与模式中其它参与者不同,因为它需要向参与者做出请求
使用__clone()函数存在限制,但这些限制可能更有助于完成更好的OOP程序
下面用一个基于OOP的实例来解释原型模式
<?php
// IAcmePrototype
abstract class IAcmePrototype
{
protected $name;
protected $id;
protected $employeePic;
protected $dept;
// Dept
abstract function setDept($orgCode);
abstract function getDept();
// Name
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;
}
// Name
public function setPic($ePic)
{
$this->employeePic = $ePic;
}
public function getPic()
{
return $this->employeePic;
}
abstract function __clone();
}
?>
<?php
// Marketing.php
include_once 'IAcmePrototype.php';
class Marketing extends IAcmePrototype
{
const UNIT = 'Marketing'; //将部门名称设置为常量方便在后面客户端调用
private $sales = "sales";
private $promotion = "promotion";
private $strategic = "stractegic planning";
public function setDept($orgCode)
{
switch ($orgCode) {
case 101:
$this->dept = $this->sales;
break;
case 102:
$this->dept = $this->promotion;
break;
case 103:
$this->dept = $this->strategic;
break;
default:
$this->dept = "Unreconized Marketing";
}
}
public function getDept(){
return $this->dept;
}
function __clone(){}
}
?>
<?php
// Client.php
function __autoload($class_name)
{
include $class_name . '.php'; //自动加载这个文件夹下面的所有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", 102, "jj101-2234",
"/jacob.png");
$this->showEmployee($Jacob);
$Ricky = clone $this->manage;
$this->setEmployee($Ricky, "Ricky Rodrigues", 203, "rr203-5634",
"/ricky.png");
$this->showEmployee($Ricky);
$Olivia = clone $this->engineer;
$this->setEmployee($Olivia, "Olivia Perez", 302, "op301-1278",
"/olivia.png");
$this->showEmployee($Olivia);
$John = clone $this->engineer;
$this->setEmployee($John, "John Smith", 301, "jj302-1454",
"/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)
{
$pic = $employeeNow->getPic(); //获取雇员的图片路径
echo "<img src=$pic width='150' height='150'><br/>";
echo $employeeNow->getName() . "<br/>";
echo $employeeNow->getDept() . ":" .
$employeeNow::UNIT . "<br>";
echo $employeeNow->getId() . "<p/>";
}
private function setEmployee(IAcmePrototype $employeeNow,
$nm, $dp, $id, $pic)
{
//根据传递进来的值,设置雇员的姓名、部门、id以及图片的路径
//这里是调用了从父类中继承过来的方法、以及自身的方法
$employeeNow->setName($nm);
$employeeNow->setDept($dp);
$employeeNow->setId($id);
$employeeNow->setPic("$pic");
}
}
$worker = new Client();
?>
上面我省略了engineer类和Management类,你可以根据Marketing直接复制然后进行修改
PS:本文参考书籍:《Learning PHP设计模式》第2部分第6章