一、簡介
相比正常創建一個對象 (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函數實現序列化和反序列化。