原型模式学习笔记
程序员文章站
2022-06-12 22:30:21
...
原型模式
原型模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过拷贝这些 原型创建新的对象
使用场景
- 类初始化消耗资源较多,或者构造函数比较复杂
- new 产生的一个对象需要非常繁琐的过程(数据准备、访问权限等),因为原型模式是在内存中对这个对象进行拷贝,要比直接new这个对象性能要好很多,在这种情况下,需要的对象越多,原型模式体现出的优点越明显
- 需要一个对象的大量公共信息,少量字段进行个性化设置的时候,或者循环体中生产大量对象时
构造函数问题
public class Protoype implements Cloneable{
public Protoype(){
System.out.println("create a new object");
}
@Override
protected Protoype clone() throws CloneNotSupportedException {
return (Protoype)super.clone();
}
public static void main(String[] args) throws CloneNotSupportedException {
Protoype protoype = new Protoype();
Protoype clone = protoype.clone();
}
}
输出:
由此可见,只输出了一次语句,使用clone()方法时,未调用构造函数
new的时候,JVM要走一趟类加载流程,这个流程非常麻烦,在类加载流程中会调用构造函数,最后生成的对象会放到堆中,而拷贝就是直接拷贝堆中的现成的二进制对象,然后重新一个分配内存块。
简单克隆(浅拷贝 Shallow Copy )
public class Protoype implements Cloneable{
private String name;
private Object o = new Object();
public Protoype(){
System.out.println("create a new object");
}
@Override
protected Protoype clone() throws CloneNotSupportedException {
return (Protoype)super.clone();
}
public static void main(String[] args) throws CloneNotSupportedException {
Protoype protoype = new Protoype();
protoype.setName("OriginalName");
Protoype clone = protoype.clone();
System.out.println("原对象名字:"+ protoype.getName() + " 拷贝对象名字:" + clone.getName());
System.out.println("name引用地址是否相同:" + (protoype.getName() == clone.getName()));
System.out.println("内部对象引用地址是否相同:" + (protoype.getO() == clone.getO()));
System.out.println("原对象:"+ protoype.getO() + " 拷贝对象名字:" + clone.getO());
}
输出结果:
从测试结果看出Object的引用地址是相同的,意味着复制的不是值,而是引用的地址。
只是完整 复制了值类型数据,没有赋值引用对象,只是将引用的指针指向了原对象
深度克隆(深拷贝 Deep Clone)
在浅拷贝中,我们只能克隆到基础的数据类型,那么实现深克隆,我们需要将引用数据类型的对象重新new出来,并且使拷贝出的对象中的引用指向新创建出的对象(包括数组)
@Override
protected Protoype clone() throws CloneNotSupportedException {
Protoype p = (Protoype)super.clone();
p.setO(new Object());
return p;
}
克隆破坏单例
如果我们克隆的目标的对象是单例对象,那意味着,深克隆就会破坏单例。实际上防止 克隆破坏单例解决思路非常简单,禁止深克隆便可。要么你我们的单例类不实现 Cloneable 接口;要么我们重写 clone()方法,在 clone 方法中返回单例对象即可
@Override protected Object clone() throws CloneNotSupportedException {
return INSTANCE;
}
源码
ArrayList 就实现了 Cloneable 接口,来看代码 clone()方法的实现:
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0; return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
上一篇: Python3之基本数据类型
下一篇: 设计模式之原型模式(Prototype)