这种模式是实现了一个原型接口,该接口用于创建当前工具的克隆。
当直接创建工具的代价比较大时,则采取这种模式。

例如,一个工具须要在一个高代价的数据库操作之后被创建。

我们可以缓存该工具,不才一个要求时返回它的克隆,在须要的时候更新数据库,以此来减少数据库调用。

原型模式phpPHP进阶教程设计模式之原型模式 Angular

我们相称于利用原型模式对一个类的实例创建一个一摸一样的副本,而我们可以重新对这个副本进行修正。

UML图

该模式中包含的角色及其职责

抽象原型类:规定了详细原型工具必须实现的接口。

详细原型类:实现抽象原型类的 clone() 方法,它是可被复制的工具。

角色实例生活例子抽象原型类PrototypeInterface手机模具抽象详细原型类Phone详细模具

紧张办理的问题

高性能创建多个相同或者类似的工具实例。

利用场景

资源优化场景。
类初始化须要消化非常多的资源,这个资源包括数据、硬件资源等。
性能和安全哀求的场景。
通过 new 产生一个工具须要非常繁琐的数据准备或访问权限,则可以利用原型模式。
一个工具多个修正者的场景。
一个工具须要供应给其他工具访问,而且各个调用者可能都须要修正其值时,可以考虑利用原型模式拷贝多个工具供调用者利用。
在实际项目中,原型模式很少单独涌现,一样平常是和工厂方法模式一起涌现,通过 clone 的方法创建一个工具,然后由工厂方法供应给调用者。

优缺陷

优点

扩展性好,由于原型模式供应了抽象原型类,在客户端针对抽象原型类进行编程,而将详细原型类写到配置文件中,增减或减少产品对原有系统都没有影响。
当创建工具的实例较为繁芜的时候,利用原型模式可以简化工具的创建过程,通过复制一个已有的实例可以提高实例的创建效率。
可以利用深克隆办法保存工具的状态,利用原型模式将工具复制一份并将其状态保存起来,以便在须要的时候利用(例如规复到历史某一状态),可赞助实现撤销操作。
创建多个相同或者类似的工具实例clone的性能比new更高

缺陷

实现原型模式每个派生类都必须实现 Clone接口须要为每一个类配置一个克隆方法,而且该克隆方法位于类的内部,当对已有类进行改造的时候,须要修正代码,违反了开闭原则。
在实现深克隆时须要编写较为繁芜的代码,而且当工具之间存在多重签到引用时,为了实现深克隆,每一层工具对应的类都必须支持深克隆,实现起来会比较麻烦。

实现思路

定义一个抽象类,所有详细类都须要继续或者实现这个抽象类都方法,里面都方法调用clone进行拷贝副本然后再返回。

代码背景

一家工厂生产手机套,在没有的时候须要把一个对应的手机型号模具做出来(相称于我们创建实例的new),所有这个手机型号的手机壳再根据这个模具来制作。

但是当我们有了一个模具之后其他的手机壳只要利用这个模具就可以快速的制造出来一个新的手机壳。

示例代码:

PrototypeInterface.php

interface PrototypeInterface{ public function copy();}

P30.php

class P30 implements PrototypeInterface{ private $model;​ private $color;​ / Sunny constructor. @param $model @param $color / public function __construct($model, $color){ $this->model = $model; $this->color = $color; }​ / @return mixed / public function getModel(){ return $this->model; }​ / @param mixed $model / public function setModel($model): void{ $this->model = $model; }​ / @return mixed / public function getColor(){ return $this->color; }​ / @param mixed $color / public function setColor($color): void{ $this->color = $color; } / 实现原型clone方法 / public function copy(){ return clone $this; }}

手机模具定义了两个属性,一个手机型号,一个颜色。
可以用光降盆不同颜色的手机壳。

调用代码:

$phone = new P30("sunny","玄色");print_r($phone);

输出结果:

P30 Object( [model:P30:private] => sunny [color:P30:private] => 玄色)$phone = new P30("sunny","玄色");echo "---------phone-----------\n";print_r($phone);$phone1 = $phone;$phone1->setColor("白色");echo "---------phone-----------\n";print_r($phone);//把稳这里打印的是$phone而不是$phone1

这样看代码没有什么问题,我们再来看一个代码。

调用代码:

$phone = new P30("sunny","玄色");echo "---------phone-----------\n";print_r($phone);$phone1 = $phone;$phone1->setColor("白色");echo "---------phone-----------\n";print_r($phone);//把稳这里打印的是$phone而不是$phone1

输出结果:

echo "---------phone-----------\n";P30 Object( [model:P30:private] => sunny [color:P30:private] => 玄色)echo "---------phone-----------\n";P30 Object( [model:P30:private] => sunny [color:P30:private] => 白色)

看第二个打印输出,我们直策应用赋值的办法来赋值给一个新的变量,原来的那个变量也被改变了。
为理解决这样的问题我们可以调用copy方法办理。

$phone = new P30("sunny","玄色");echo "---------phone-----------\n";print_r($phone);$phone1 = $phone->copy();$phone1->setColor("白色");echo "---------phone-----------\n";print_r($phone);echo "---------phone1-----------\n";print_r($phone1);

输出结果:

---------phone-----------P30 Object( [model:P30:private] => sunny [color:P30:private] => 玄色)---------phone-----------P30 Object( [model:P30:private] => sunny [color:P30:private] => 玄色)---------phone1-----------P30 Object( [model:P30:private] => sunny [color:P30:private] => 白色)

调用了copy之后里面的属性全部都同等,我们也可以再次进行修正而不会影响之前的工具,我们修正的只是一份一样的副本而已。

如果以为文章还不错,请把文章分享给更多的人学习,在文章中创造有误的地方也希望各位指出更正。
现有误的地方也希望各位指出更正。