概念
用原型實例指定創建物件的種類,並且透過拷貝這些原型創建新的物件。
Prototype原型模式是一種創建型設計模式,Prototype模式允許一個物件再創建另一個可自訂的對象,根本無需知道任何如何創建的細節。
工作原理
透過將一個原型對象傳給那個要發動創建的對象,這個要發動創建的對象通過請求原型對象拷貝它們自己來實施創建。
解決什麼問題
它主要面對的問題是:「某些結構複雜的物件」的創建工作;由於需求的變化,這些物件經常面臨著劇烈的變化,但是他們卻擁有比較穩定一致的接口。
角色
抽象原型(Prototype)角色:聲明一個克隆自身的介面
具體原型(Concrete Prototype)角色:實作一個複製自身的運算
結構圖
直接copy,拷貝了來源物件的引用位址等,所以原來內容變化,新內容變化。
<?php header('Content-type:text/html;charset=utf-8'); /** * PHP原型模式-潜拷贝 */ /** * Interface Prototype 抽象原型模式 */ interface Prototype { // 定义拷贝自身方法啊 public function copy(); } /** * Class ConcretePrototype 具体原型模式 */ 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; } /** * 拷贝自身 * * @return ConcretePrototype 返回自身 */ public function copy() { return clone $this;//浅拷贝 } } /** * 测试潜拷贝 */ class LatentCopyDemo{ public $array; } /** * Class Client 客户端 */ class Client{ /** * 测试方法 */ public static function test(){ $demo = new LatentCopyDemo(); $demo->array = array(1,2); $object1 = new ConcretePrototype($demo); $object2 = $object1->copy(); var_dump($object1->getName()); echo '<br/>'; var_dump($object2->getName()); echo '<br/>'; $demo->array = array(3, 4); var_dump($object1->getName()); echo '<br />'; var_dump($object2->getName()); echo '<br />'; } } Client::test();
運行結果
object(LatentCopyDemo)#1 (1) { ["array"]=> array(2) { [0]=> int(1) [1]=> int(2) } } object(LatentCopyDemo)#1 (1) { ["array"]=> array(2) { [0]=> int(1) [1]=> int(2) } } object(LatentCopyDemo)#1 (1) { ["array"]=> array(2) { [0]=> int(3) [1]=> int(4) } } object(LatentCopyDemo)#1 (1) { ["array"]=> array(2) { [0]=> int(3) [1]=> int(4) } }
深拷貝模式
深copy透過序列化和反序列化完成copy,新copy的內容完全複製原來的內容。原來的內容變化,新內容不變。
<?php header('Content-type:text/html;charset=utf-8'); /** * PHP原型模式-深拷贝 */ /** * Interface Prototype 抽象原型模式 */ interface Prototype { // 定义拷贝自身方法啊 public function copy(); } /** * Class ConcretePrototype 具体原型模式 */ 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; } /** * 拷贝自身 * * @return ConcretePrototype 返回自身 */ public function copy() { $serialize_obj = serialize($this); $clone_obj = unserialize($serialize_obj); return $clone_obj; } } /** * 测试潜拷贝 */ class DeepCopyDemo{ public $array; } /** * Class Client 客户端 */ class Client{ /** * 测试方法 */ public static function test(){ $demo = new DeepCopyDemo(); $demo->array = array(1,2); $object1 = new ConcretePrototype($demo); $object2 = $object1->copy(); var_dump($object1->getName()); echo '<br/>'; var_dump($object2->getName()); echo '<br/>'; $demo->array = array(3, 4); var_dump($object1->getName()); echo '<br />'; var_dump($object2->getName()); echo '<br />'; } } Client::test();
運行結果
object(DeepCopyDemo)#1 (1) { ["array"]=> array(2) { [0]=> int(1) [1]=> int(2) } } object(DeepCopyDemo)#4 (1) { ["array"]=> array(2) { [0]=> int(1) [1]=> int(2) } } object(DeepCopyDemo)#1 (1) { ["array"]=> array(2) { [0]=> int(3) [1]=> int(4) } } object(DeepCopyDemo)#4 (1) { ["array"]=> array(2) { [0]=> int(1) [1]=> int(2) } }
優點和缺點
優點
1、可以在運行時刻增加和刪除產品
2、可以改變值以指定新物件
3、可以改變結構以指定新物件
4、減少子類別的建構
5、用類別動態配置應用
缺點
Prototype模式的最主要缺點就是每一個類別必須配備一個克隆方法。而且這個克隆方法需要對類別的功能進行通盤考慮,這對全新的類別來說不是很難,但對已有的類別進行改造時,不一定是件容易的事。
適用場景
當一個系統應該獨立於它的產品創建、構成和表示時,要使用Prototype模式
當要實例化的類別是在運行時刻指定時,例如動態載入
為了避免創建一個與產品類別層級平等的工廠類別層級時;
當一個類別的實例只能有幾個不同狀態組合中的一種。建立相應數目的原型並克隆它們可能比每次用合適的狀態手動實例化該類別更方便一些