什么是原型模式
原型模式是先创建好一个原型对象,然后通过clone原型对象来创建新的对象。适用于大对象的创建,因为创建一个大对象需要很大的开销,如果每次new就会消耗很大,原型模式仅需内存拷贝即可。
角色分析:
- Prototype(抽象原型角色):声明一个克隆自身的接口
- Concrete Prototype(具体原型角色):实现一个克隆自身的操作
拷贝对象的两种方式
浅拷贝:
被拷贝对象的所有变量都含有与原对象相同的值,而且对其他对象的引用仍然是指向原来的对象。
即 变量之间是地址传递的;对象之间同时指向一个地址,大家共享一个地址。
赋值时,引用赋值,相当于取了一个别名。对其中一个修改,会影响另一个。
深拷贝:
被拷贝对象的所有的变量都含有与原来对象相同的值,除了那些引用其他对象的变量。那些引用其他对象的变量将指向一个被拷贝的新对象,而不再是原有那些被引用对象。
即 变量被复制了一份,值传递,深拷贝把要拷贝的对象所引用的对象也都拷贝了一次,而这种对被引用到的对象拷贝叫做间接拷贝。
赋值时值完全复制,完全的copy,对其中一个作出改变,不会影响另一个。
深拷贝要深入到多少层,是一个不确定的问题。
在决定以深拷贝的方式拷贝一个对象的时候,必须决定对间接拷贝的对象是采取浅拷贝还是深拷贝还是继续采用深拷贝。
因此,在采取深拷贝时,需要决定多深才算深。此外,在深拷贝的过程中,很可能会出现循环引用的问题。
利用序列化来做深拷贝:
利用序列化来做深拷贝,把对象写到流里的过程是序列化(Serilization)过程,但在业界又将串行化这一过程形象的称为“冷冻”或“腌咸菜”过程;而把对象从流中读出来的过程则叫做反序列化(Deserialization)过程,也称为“解冻”或“回鲜”过程。
在PHP中使用serialize和unserialize函数实现序列化和反序列化。
区别:
浅拷贝是拷贝一层,深层次的对象级别的就拷贝引用;深拷贝是拷贝多层,每一级别的数据都会拷贝出来。
应用场景
需要的对象已经创建过,可考虑复制、克隆对象,避免再次创建对象。
PHP 代码实现
<?php
/**
* 原型模式
* Class Prototype
*/
abstract class Prototype
{
/**
* 克隆对象
* @param bool|false $isDeep 是否深拷贝 true 深拷贝,false 浅拷贝
* @return mixed
*/
abstract public function cloned($isDeep = false);
}
/**
* 具体原型类
* Class Plane
*/
class Plane extends Prototype
{
public $color;
public function Fly()
{
echo "飞机飞啊飞!" . $this->color . '<br/>';
}
/**
* 具体实现拷贝方法
* @param bool|false $isDeep 是否深拷贝 true 深拷贝,false 浅拷贝
* @return mixed|Plane
*/
public function cloned($isDeep = false)
{
//深拷贝
if($isDeep){
$serialize_obj = serialize($this);
$clone_obj = unserialize($serialize_obj);
return $clone_obj;
}
//浅拷贝
return clone $this;
}
}
//=======================原型模式测试===============================
$plane1 = new Plane();
$plane1->color = "Blue";
$plane2 = $plane1->cloned(true);
$plane1->Fly();
$plane2->Fly();
//结果
//飞机飞啊飞!Blue
//飞机飞啊飞!Blue