GOF23-原型模式

原型模式:以现有对象为原型,克隆新的一模一样的对象。减少通过构造方法新建对象时分配属性、方法的权限时间。

原型方法实现方式:实现Cloneable接口(标记接口)和Object.clone()方法、序列化实现复制。

一、实现Cloneable接口(标记接口)和Object.clone()方法(在破解单例模式中使用过)

通过java提供的Cloneable接口方式实现原型模式,分为浅克隆和深克隆。 

1.浅克隆

package prototype;

import java.util.Date;

public class Sheep implements Cloneable{
    //基本类型
    private String name;
    //对象
    private Date birthday;
    /**
     * 此方法在object方法中 Cloneable接口是一个空接口 调用的是本地方法
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Sheep obj = (Sheep) super.clone();
        return obj;
    }

    public String getName() {
        return name;
    }

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

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

测试代码

package prototype;

import java.util.Date;

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Sheep sheep = new Sheep();
        sheep.setName("小羊");
        sheep.setBirthday(new Date(123213));
        
        Sheep sheep2 = (Sheep) sheep.clone();
        Date birthday = sheep.getBirthday();
        birthday.setTime(123312323);
        sheep.setName("大羊");
        
        System.out.println(sheep.getName());
        System.out.println(sheep.getBirthday().toString());
        System.out.println(sheep2.getName());
        System.out.println(sheep2.getBirthday().toString());
    }
}

结果

总结:通过object的clone方法克隆的对象,当对象的属性为非基本类型时,克隆对象和被克隆对象中是同一个对象。内存示意图如下克隆是克隆属性的值(在java中全是值传递,当属性为非基本类型时属性存储的是 对象内存地址的值)

2.深克隆

为了解决上一问题,我们需要对象也为新克隆出来的对象。 那么我们需要重写clone方法。

@Override
protected Object clone() throws CloneNotSupportedException {
    Sheep obj = (Sheep) super.clone();
    obj.birthday = (Date) this.birthday.clone();
    return obj;
}

增加了属性对象的单独克隆obj.birthday = (Date) this.birthday.clone(); 实现深克隆

二、通过序列化实现深克隆

序列化对象实现Serializable接口 ,其他不用修改

测试代码

package prototype;

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

public class Client2 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Sheep sheep = new Sheep();
        sheep.setName("小羊");
        sheep.setBirthday(new Date(123213));
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(sheep);
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        Sheep sheep2 = (Sheep) ois.readObject();
        sheep.getBirthday().setTime(11111111);
        System.out.println(sheep.getName());
        System.out.println(sheep.getBirthday().toString());
        System.out.println(sheep2.getName());
        System.out.println(sheep2.getBirthday().toString());
    }
}

测试结果

三、性能对比,测试代码都是根据实际使用代码,如你有差异,请指出共同勉进,谢谢

package prototype;

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

public class Client3 {
    static int MAXCYCLIC = 100000;
    public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
        Sheep sheep = new Sheep();
        sheep.setName("小羊");
        sheep.setBirthday(new Date(123213));

        Long start = System.currentTimeMillis();
        for(int i=0; i<MAXCYCLIC;i++){
            Sheep sheep1 = new Sheep();
            sheep.setName("小羊");
            sheep.setBirthday(new Date(123213));
        }
        Long end = System.currentTimeMillis();
        System.out.println("构造方法创建对象所需时间"+(end-start));

        start = System.currentTimeMillis();
        for(int i=0; i<MAXCYCLIC;i++){
            Sheep sheep1 = (Sheep) sheep.clone();
        }
        end = System.currentTimeMillis();
        System.out.println("克隆接口方式创建对象所需时间"+(end-start));

        start = System.currentTimeMillis();
        for(int i=0; i<MAXCYCLIC;i++){
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(sheep);
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            Sheep sheep2 = (Sheep) ois.readObject();
            ois.close();
            bais.close();
            oos.close();
            baos.close();
        }
        end = System.currentTimeMillis();
        System.out.println("序列化方式创建对象所需时间"+(end-start));

    }
}

测试结果(每次结果根据电脑资源情况 会不一致):序列化方式因为存在 输入输出流的创建和关闭非常耗资源和时间。

 

总结:接口克隆方式性能高但是我们需要更关注代码的实现,序列化方式简单粗暴,但是性能相对低, 看具体情况择优选择。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章