欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

原型模式学习笔记

程序员文章站 2022-06-12 22:30:21
...

原型模式

原型模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过拷贝这些 原型创建新的对象

使用场景

  1. 类初始化消耗资源较多,或者构造函数比较复杂
  2. new 产生的一个对象需要非常繁琐的过程(数据准备、访问权限等),因为原型模式是在内存中对这个对象进行拷贝,要比直接new这个对象性能要好很多,在这种情况下,需要的对象越多,原型模式体现出的优点越明显
  3. 需要一个对象的大量公共信息,少量字段进行个性化设置的时候,或者循环体中生产大量对象时

构造函数问题

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); 
	}
}