原型模式(Prototype)

当我需要创建多个相同的对象时,若通过new 创建对象比较费时费力,那么可以通过克隆来创建一个一样的新对象,即通过原型创建新对象。

 原型模式大大节省资源测试


 

克隆方式:

  实现Cloneable接口(声明接口:声明此方法可以克隆),重写Object类的clone方法。

浅克隆:被Clone的对象的所有变量都含有原来对象相同的值,而引用变量还是原来对用的引用。

深克隆:被克隆对象的所有变量都含有原来的对象相同的值,引用变量也重新复制了一份。

实现方式:

  1、在clone对象内对引用属性进行克隆。2、使用反序列化进行克隆。


 

1、原型模式,但是浅克隆:

无视引用变量可能造成的影响。

例子:

import java.util.Date;
/**
 * 克隆猪猪,它支持被克隆。
 */
public class ClonePig implements Cloneable{
    private String name;//姓名
    private Date birthday;//生日

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object obj = super.clone();
        return obj;//调用父类的克隆方法。
    }

    //此处的birthday指向的是传过来的Date对象的地址,那个对象改变会导致birthday改变
    public ClonePig(String name, Date birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    public String getName() { return name; }

    public Date getBirthday() { return birthday; }

    public void setBirthday(Date birthday) { this.birthday = birthday; }

    public void setName(String name) { this.name = name; }
}

测试代码:

import java.util.Date;

public class Client {
    public static void main(String[] args) throws Exception {
        //准备一个Daye,等会儿把date作为猪猪的属性传进去,修改date会导致猪猪的属性更改
        Date date = new Date(111111111l);

        //我有一个22年的叫做佩奇的猪猪
        ClonePig pig = new ClonePig("佩奇", date);

        //通过克隆获取一直一模一样的猪猪
        ClonePig clonePig1= (ClonePig) pig.clone();

        System.out.println("-----------------刚刚克隆出来,使用的同一个时间对象:data");
        System.out.println("pig birthday:"+pig.getBirthday().getTime());
        System.out.println("clonePig1 birthday:"+clonePig1.getBirthday().getTime());

        System.out.println("-------------------修改共同的引用对象,data");
        //通过修改date,直接改变佩奇的出生时间
        date.setTime(222222222l);
        //佩奇二号的出生日也变了!因为他们的Date对象是用的同一个。
        System.out.println("pig birthday:"+pig.getBirthday().getTime());
        System.out.println("clonePig1 birthday:"+clonePig1.getBirthday().getTime());


        System.out.println("-------------------通过set方法给pig新的Date对象");
        //通过set方法改变佩奇的出生时间
        pig.setBirthday(new Date(333333333333l));
        //佩奇二号的出生日不会变,此时pig的birthday为新创建的对象。
        System.out.println("pig birthday:"+pig.getBirthday().getTime());
        System.out.println("clonePig1 birthday:"+clonePig1.getBirthday().getTime());

        System.out.println("--------------------再次修改date,只有clonePig改变");
        date.setTime(444444444444l);
        //只有克隆佩奇会变。
        System.out.println("修改之后pig:"+pig.getBirthday().getTime());
        System.out.println("修改之后:"+clonePig1.getBirthday().getTime());
    }
}

运行结果:

 

 

 2、原型模式,但是深克隆(修改clone方法):

把引用类型的属性也克隆一份,修改clone方法为:

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object obj = super.clone();
        
        //解决浅克隆使用同一个引用地址的情况,把属性也克隆一份。
        ClonePig clonePig = (ClonePig) obj;
        clonePig.birthday = (Date) this.birthday.clone();
        return clonePig;//调用父类的克隆方法。
    }

再次运行测试代码:此时克隆出来的clonePig丝毫不受影响,完全独立。

 

 

 3、原型模式,但是使用反序列化实现深克隆

总所周知,反序列化的时候会重新创建一个对象,也包括属性对象(除非你序列化的类重写了readResolve方法)。

实现:ClonePig实现可序列号接口。

import java.io.Serializable;
import java.util.Date;
/**
 * 克隆猪猪,它支持被序列化
 */
public class ClonePig implements Serializable {
    private String name;//姓名
    private Date birthday;//生日

    //此处的birthday指向的是传过来的Date对象的地址,那个对象改变会导致birthday改变
    public ClonePig(String name, Date birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    public String getName() { return name; }

    public Date getBirthday() { return birthday; }

    public void setBirthday(Date birthday) { this.birthday = birthday; }

    public void setName(String name) { this.name = name; }
}

对其进行序列号,然后反序列化克隆出新的对象(深克隆)。

import java.io.*;
import java.util.Date;

public class Client {
    public static void main(String[] args) throws Exception {
        Date date = new Date(1111111L);
        ClonePig pig = new ClonePig("佩奇",date);

        //序列化,把pig写入字节数组中
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(pig);
        byte[] obj = baos.toByteArray();

        //反序列化,把字节数组内容还原为一个ClonePig对象
        ByteArrayInputStream bais = new ByteArrayInputStream(obj);
        ObjectInputStream ois = new ObjectInputStream(bais);
        ClonePig clonePig = (ClonePig) ois.readObject();

        //测试
        date.setTime(2222222222L);
        System.out.println("pig:"+pig.getBirthday().getTime());
        System.out.println("clonePig:"+clonePig.getBirthday().getTime());
    }
}

运行结果:

 

posted @ 2022-11-23 19:42  在博客做笔记的路人甲  阅读(68)  评论(0编辑  收藏  举报