一、简介
相比正常创建一个对象 (new Foo () ),首先创建一个原型,然后克隆它会更节省开销。
原型模式是先创建好一个原型对象,然后通过clone原型对象来创建新的对象。适用于大对象的创建,因为创建一个大对象需要很大的开销,如果每次new就会消耗很大,原型模式仅需内存拷贝即可。
二、场景
比如:
- 大量的数据对象(比如通过ORM获取1,000,000行数据库记录然后创建每一条记录对应的对象实体)
三、类结构
原型模式主要角色如下:
角色 | 类别 | 简述 |
---|---|---|
Prototype | 抽象原型角色 | 声明一个克隆自身的接口 |
Concrete Prototype | 具体原型角色 | 实现一个克隆自身的操作 |
四、UML图
五、代码分析
1、抽象原型角色
interface Prototype
{
public function shallowCopy();
public function deepCopy();
}
2、具体原型角色
class ConcretePrototype implements Prototype
{
private $_name;
public function __construct($name){
$this->_name = $name;
}
public function setName($name){
$this->_name = $name;
}
public function getName(){
return $this->_name;
}
//浅拷贝
public function shallowCopy(){
return clone $this;
}
//深拷贝
public function deepCopy() {
$serialize_obj = serialize($this);
$clone_obj = unserialize($serialize_obj);
return $clone_obj;
}
}
3、使用案例
class Demo
{
public $string;
}
class UsePrototype
{
//测试浅拷贝
public function shallow(){
$demo = new Demo();
$demo->string = "susan";
$object_shallow_first = new ConcretePrototype($demo);
$object_shallow_second = $object_shallow_first->shallowCopy();
var_dump($object_shallow_first->getName());
echo '<br/>';
var_dump($object_shallow_second->getName());
echo '<br/>';
$demo->string = "sacha";
var_dump($object_shallow_first->getName());
echo '<br/>';
var_dump($object_shallow_second->getName());
echo '<br/>';
}
//测试深拷贝
public function deep(){
$demo = new Demo();
$demo->string = "Siri";
$object_deep_first = new ConcretePrototype($demo);
$object_deep_second = $object_deep_first->deepCopy();
var_dump($object_deep_first->getName());
echo '<br/>';
var_dump($object_deep_second->getName());
echo '<br/>';
$demo->string = "Demo";
var_dump($object_deep_first->getName());
echo '<br/>';
var_dump($object_deep_second->getName());
echo '<br/>';
}
}
$up = new \Libs\UsePrototype;
$up->shallow();
echo '<hr>';
$up->deep();
结果如下:
object(Demo)#2 (1) { ["string"]=> string(5) "susan" }
object(Demo)#2 (1) { ["string"]=> string(5) "susan" }
object(Demo)#2 (1) { ["string"]=> string(5) "sacha" }
object(Demo)#2 (1) { ["string"]=> string(5) "sacha" }
--------------------------------------------------------------
object(Demo)#5 (1) { ["string"]=> string(4) "Siri" }
object(Demo)#8 (1) { ["string"]=> string(4) "Siri" }
object(Demo)#5 (1) { ["string"]=> string(4) "Demo" }
object(Demo)#8 (1) { ["string"]=> string(4) "Siri" }
注意:在PHP中,对象本身就是引用传递。
六、特点
1、浅拷贝
被拷贝对象的所有变量都含有与原对象相同的值,而且对其他对象的引用仍然是指向原来的对象。即浅拷贝只负责当前对象实例,对引用的对象不做拷贝。
2、深拷贝
被拷贝对象的所有的变量都含有与原来对象相同的值,除了那些引用其他对象的变量。那些引用其他对象的变量将指向一个被拷贝的新对象,而不再是原有那些被引用对象。
即深拷贝把要拷贝的对象所引用的对象也都拷贝了一次,而这种对被引用到的对象拷贝叫做间接拷贝。
3、序列化深拷贝
利用序列化来做深拷贝,把对象写到流里的过程是序列化的过程,这一过程称为“冷冻”或“腌咸菜”,反序列化对象的过程叫做“解冻”或“回鲜”。
在PHP中使用serialize和unserialize函数实现序列化和反序列化。