原型模式用于创建重复的对象,同时又能保证性能。
当需要复制某个对象,并且该对象创建的代价比较大时,就可以使用原型模式,比如某数据从数据库中查询得到,可以将该对象进行缓存,下一次请求时返回该数据的克隆,减少对数据库的调用。
示例场景:
游戏中人物发射的子弹,每次发射都进行创建的话对性能会造成很大的影响,可以使用原型模式来拷贝子弹对象。
创建一个子弹类,实现Cloneable接口,使其可以被克隆:
package com.cc.prototype;
public class Bullet implements Cloneable {
public Bullet() {
try {
// 模拟子弹创建耗时
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
测试一下:
package com.cc.prototype2;
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
{
// 没使用原型模式
// for (int i = 0; i < 100; i++) {
// Bullet bullet = new Bullet();
// System.out.println(bullet);
// }
}
{
// 使用原型模式
Bullet originBullet = new Bullet();
for (int i = 0; i < 100; i++) {
Bullet bullet = (Bullet) originBullet.clone();
System.out.println(bullet);
}
}
}
}
测试模块中,注释的部分是没有使用克隆,每一个bullet创建都需要1秒(模拟耗时),所以创建100个bullet需要100秒。使用了原型模式后,复制对象不走构造方法,它基于内存二进制流的复制,在性能上比直接new一个对象更加好。
原型模式的缺点:
- 被克隆的类需要实现Cloneable接口
- clone方法位于类内部,当对已有类进行改造时,需要修改代码,违反开闭原则
- 当实现深克隆时,且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象都必须支持深克隆,实现起来比较麻烦