实质就是 对象的复制
对一些大型对象,每次去 new,初始化开销很大,这个时候我们 先 new 一个模版对象,然后其他实例都去 clone 这个模版, 这样可以节约不少性能。
这个所谓的模版,就是原型(Prototype);
当然,原型模式比单纯的 Clone 要稍微升级一下。
普通 clone
new 和 clone 都是用来创建对象的方法。
在 PHP 中, 对象间的赋值操作实际上是引用操作 (事实上,绝大部分的编程语言都是如此! 主要原因是内存及性能的问题) ,比如:
1 2 3 4 5 6 7 8 9 10 11
| class ProClass { public $data; }
$obj1 = new ProClass(); $obj1->data = "aaa"; $obj2 = $obj1; $obj2->data = "bbb";
var_dump($obj1->data);
|
但是如果你不是直接引用,而是 clone,那么相当于做了一个独立的副本:
1 2
| $obj2 = clone $obj1; $obj2->data ="bbb";
|
这样就得到一个和被复制对象完全没有纠葛的新对象,但两个对象长得是一模一样的。
浅复制和深复制
如果你以为你已经把它俩彻底分开了,你错了,没那么容易, 我们再看一个复杂点例子。
继续接着上面的例子看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| class ProClass { public $data; public $item; }
$obj1 = new ProClass(); $obj1->data = "aaa";
class itemObject { public $count = 0;
public function add() { $this->count = ++$this->count; } }
$item = new itemObject; $obj1->item = $item; $obj2 = clone $obj1;
$obj2->data = "bbb";
var_dump($obj1->data); var_dump($obj2->data);
$obj2->item->add();
print_r($item); print_r($obj1); print_r($obj2);
|
我们既然要 Clone,目的就是要把 两个对象 完全分离开。
所以我们来聊一下 深复制
的方法:
非常简单,在被复制对象中加一个魔术方法就可以了。
1 2 3 4 5 6 7 8
| class ProClass { public $data; public $item; public function __clone() { $this->item = clone $this->item; } }
|
正解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| interface Prototype { public function copy(); }
class ConcretePrototype implements Prototype { private $_name;
public function __construct($name) { $this->_name = $name; }
public function copy() { return clone $this; } }
class Demo { }
$demo = new Demo(); $object1 = new ConcretePrototype($demo); $object2 = $object1->copy();
|
从上面的例子不难看出,所谓原型模式就是不直接用 clone 这种关键字写法,而是创建一个原型类。
把需要被复制的对象丢进 原型类里面,然后这个类就具有了 复制自己的能力(方法),并且可以继承原型的一些公共的属性和方法。