先抛开程序观念,通过一个简单的例子,来说明一下原型设计模式的好处:
我们慢慢用键盘打字,写了一封邮件。发出去后,发现有些人漏发了,要再发一次。接下来,你会直接复制刚才发的邮件内容,而不是从头开始重新写邮件,复制过来的邮件内容,你发觉里面的称呼,不适合当前的收件人,你还可以去修改邮件内容,但这并不会影响你刚才已经发出去的邮件。其中复制内容、可修改就是本文要讲的原型设计模式的好处。
原型设计模式的好处:
创建快,可修改
废话不多说,下面直接结合程序代码,再来理解一下这个原型设计模式。
<?php
//轮胎类
class Wheel{
//轮胎半径
private $radius = 10;
public function setRadius($value){
$this->radius = $value;
}
}
//车门类
class Door{
}
//小汽车类
class Car{
private $wheel;
private $door;
//车内温度
private $temperature;
public function __construct(Wheel $wheel, Door $door)
{
$this->wheel = $wheel;
$this->door = $door;
echo "--- new a car construct ----<br>";
$this->temperature = 30;
}
public function setTemperature($newValue){
$this->temperature = $newValue;
}
}
$wheel = new Wheel();
$door = new Door();
$car1 = new Car($wheel, $door);
$car2 = clone $car1; //拷贝原型对象
$car2->setTemperature(25);
var_dump($car1);
var_dump($car2);
上面程序在浏览器打印结果如下:
--- new a car construct ----
F:\wamp\www\design\prototype\clone.php:49:
object(Car)[3]
private 'wheel' =>
object(Wheel)[1]
private 'radius' => int 10
private 'door' =>
object(Door)[2]
private 'temperature' => int 30
F:\wamp\www\design\prototype\clone.php:50:
object(Car)[4]
private 'wheel' =>
object(Wheel)[1]
private 'radius' => int 10
private 'door' =>
object(Door)[2]
private 'temperature' => int 25
原型设计模式就是通过拷贝(clone)原型对象来新建对象,而不是通过new关键字来创建对象。
有什么好处?
从上面打印结果就可以看出来:
1. clone对象,不用执行原型对象的构造函数。对应“创建快”的优点
解析:上面输出的new a car construct 内容,是new Car类时执行构造函数时输出的。构造函数里面的工作,就类似上面例子中的打字写信的过程。clone对象,就不会执行原型类Car的构造函数,就相当于省掉了重新打字写信的过程。
2.新对象属性可修改,不会影响其它同类对象。对应“可修改”的优点
解析:上面输出就可以看出,car2对象车内温度设置为25摄氏度后,car1对象车内温度仍然是30度,并不会跟着变化。
从“可修改”的优点出发,拷贝还可以分为“深拷贝”和“浅拷贝”。上面的代码实现的是“浅拷贝”,实际应用大多都是“深拷贝”。
那么什么是深拷贝和浅拷贝呢?
先继续利用上面程序,来说说浅拷贝是怎么回事儿?
在上面程序末尾添加如下两行代码:
$wheel->setRadius(20);
var_dump($car2);
打印结果如下:
F:\wamp\www\design\prototype\clone.php:52:
object(Car)[4]
private 'wheel' =>
object(Wheel)[1]
private 'radius' => int 20
private 'door' =>
object(Door)[2]
private 'temperature' => int 25
你关注下车轮半径值,由10变为20了,有什么问题么?
......
问题就在于:
我修改的wheel类是用于创建car1对象的,却影响到了car2对象。通俗点说,我在改一辆车的轮胎大小,另一辆车的轮胎大小也跟着同样变化了,这就是浅拷贝所带来的问题。
翟码农自己给浅拷贝下一个定义:
浅拷贝:针对原对象的属性和方法,所有拷贝类拥有独立的一份。但对于依赖的类对象,所有拷贝类依赖的类对象都是同一个(即依赖的类对象在内存里都是共同的区域)。
深拷贝就是解决浅拷贝的问题而产生的概念。
php里深拷贝如何实现呢?
在上面程序里Car类里添加如下方法:
public function __clone()
{
echo "--- enter clone function ---<br>";
$this->wheel = clone $this->wheel;
$this->door = clone $this->door;
}
__clone是魔术方法,在使用clone关键字时,会自动调用原型类的这个方法。
再看上面程序里car2对象的内容,就会发现车轮半径是10了。在末尾再次打印car1对象内容,发现车轮半径改成20了。
这就说明,此时car1对象和car2对象依赖的车轮类对象都是独立的了。这就是我们所说的深拷贝。
原型设计模式的应用场景:
通篇下来,就可以理解,当需要大量创建某种类的实例时,就可以采用此模式,避免执行构造函数,减少内存消耗,节省时间,即加快了实例的生成。
本文为翟码农个人博客里有关原型设计模式的原创文章,转载请注明出处:http://www.zhai14.com/blog/design-pattern-of-prototype.html
- 2020年03月25日 18:27文章创建
- 2020年03月26日 00:49文章发布