設計模式[創建型]07--原型模式(Prototype)

一、簡介

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章