设计模式:原型模式

定义

原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。

原型模式是直接基于内存二进制流进行复制,不调用构造函数,新对象的创建时间大大缩短。

Jdk浅克隆

jdk中,不需要手动创建原型接口,因为jdk中已经内置了Cloneable原型接口,自定义的原型类只需要实现该接口并重写clone方法即可完成类的复制。

//setter getter tostring省略
public class Prototype implements Cloneable{

    private String name;

    private Integer age;

    private Date date;

    //注意clone需要改成public修饰
    @Override
    public Prototype clone() throws CloneNotSupportedException {
        return (Prototype)super.clone();
    }

}

浅克隆测试:

    public static void main(String[] args) throws CloneNotSupportedException {
        Prototype prototype = new Prototype();
        prototype.setAge(1);
        prototype.setName("wj");
        prototype.setDate(new Date());


        Prototype clone = prototype.clone();
        System.out.println(clone);
        System.out.println(prototype);

        clone.getDate().setTime(0);
        System.out.println(clone);
        System.out.println(prototype);
    }

image-20201225105002215

我们发现:修改了克隆类的引用对象后,原对象也发生修改。

原因:类中存在引用对象属性,则原型对象与克隆对象的该属性会只想同一对象的引用。

Jdk浅克隆升级版(深克隆)

public class Prototype implements Cloneable{

    private String name;

    private Integer age;

    private Date date;

    @Override
    public Prototype clone() throws CloneNotSupportedException {
        Prototype clone = (Prototype)super.clone();
        Date dateClone = (Date)clone.getDate().clone();
        clone.setDate(dateClone);
        return clone;
    }
}

再使用上述方法进行测试:

image-20201225110007490

发现修改了clone对象,原对象没有修改。这是因为再super.clone()后,手动给克隆对象的相关属性分配给另一块内存。

不过有一个弊端:当原型对象中有很多引用属性的时候,手动分配十分麻烦,并且引用属性也要重写clone接口。

序列化实现深克隆

需要实现Cloneable,Serializable

public class Prototype implements Cloneable,Serializable {

    private String name;

    private Integer age;

    private Date date;

    @Override
    public Prototype clone() throws CloneNotSupportedException {

        try{
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);

            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            return (Prototype)ois.readObject();
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
}

从结果上看,实现了深克隆。

image-20201225112535432

克隆破坏单例模式

如果单例对象实现了克隆接口,然后我们重写了clone方法并调用,这样会创建出一个新的单例对象,破坏了单例模式。

解决方案如下:

  • 单例对象不实现Cloneable接口

  • 重写clone方法:

    @Override
    public Prototype clone(){
        return instance;//instance 就是单例对象,只需要直接返回即可
    }
    
原文地址:https://www.cnblogs.com/wwjj4811/p/14188382.html