设计模式之原型模式
1. 定义
对象在创建时通过克隆现有对象而不是通过实例化新对象来创建
2. 口语化举例
克隆,这种方式在生物界太常见了,比如教科书里典型的例子,克隆羊多利:克隆羊_百度百科 (baidu.com)
为什么要克隆?
- 需要一个新的产品(羊🐏),要和原来的一样,克隆的方式可以直接复刻DNA,甚至都不需要关注DNA信息具体是什么
为什么不采用新建一个产品(羊🐏)的方式?
- 这方式太复杂了,如何才能新建一只羊,并且还得和原来的羊保持一样,DNA信息难以解读,难以复刻
克隆,这就是典型的原型模式场景
(下面的描述会沿用这个上述这个场景)
3. 源码示例
Three.js是著名的WebGL库,其源码中几乎每个对象都实现了clone()
方法,也就是说,Three.js广泛应用了原型模式
例如,常用的向量对象Vector3
,其源码大体如下:
class Vector3 {
constructor( x = 0, y = 0, z = 0 ) {
Vector3.prototype.isVector3 = true;
this.x = x;
this.y = y;
this.z = z;
}
clone() {
return new this.constructor( this.x, this.y, this.z );
}
copy( v ) {
this.x = v.x;
this.y = v.y;
this.z = v.z;
return this;
}
// ...
}
上述代码,可以看出向量对象Vector3
可以使用clone()
函数克隆出一个和自己一模一样的新对象
和new Vector3()
这种方式相比,还得知道原来的Vector3
得具体数据是什么,这就显得简单多了
4. 总结
4.1 设计优点
-
可以克隆对象而无需关注它原来有什么具体信息
-
可以更方便地生成复杂对象
4.2 适用场景
-
需要复制一些对象
基于内存地址引用的代码对象通常需要考虑这个问题,因为在某个地方改变了引用的对象的数据,那么将影响所有使用这个数据的代码
4.3 JavaScript中的原型
JavaScript中的原型与原型模式不一样,JavaScript中的原型是为了实现面向对象的继承
在JavaScript中,每个对象都有一个指向另一个对象的引用,这个对象就是原型
当我们访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,JavaScript会去查找它的原型对象,如果原型对象中有这个属性或方法,就会返回它的值,这个过程叫原型链
5. 参考资料
[1] 原型设计模式 (refactoringguru.cn)
[2] three.js/src/math/Vector3.js at dev · mrdoob/three.js (github.com)