JAVA设计模式之 3.原型设计模式,以及浅克隆与深克隆。

解决某些entity大量属性的重用率很高,手动设置过于繁琐且无必要的问题。

先看原型设计模式之浅拷贝

//原型模式
public class Prototype {
    public static void main (String[] args) throws CloneNotSupportedException {
        Report report = new Report();
        report.setId (1);
        report.setName("mary");
        report.setAge(80);
        System.out.println(report.toString());

        //当Report的参数很多,重复属性又很大时,先clone,再修改差异值,就节约很多时间。
        Report report1 = (Report) report.clone();
        report1.setName("Tom");
        System.out.println(report1.toString());

        Report report2 = (Report) report.clone();
        System.out.println(report == report2);
    }
}

@Data
class Report implements Cloneable {
    private int id;
    private String name;
    private int age;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

优点:clone直接得到一个模板原型对象,方便,clone是直接复制内存中的2进制信息,效率很高。

ps:report == report2  FALSE 地址不相等。所以复制会破坏单例对象,单例对象应该禁止克隆。

缺点:直接上代码

//原型模式
public class Prototype {
    public static void main (String[] args) throws CloneNotSupportedException {
        Report report = new Report();
        report.setId (1);
        report.setName("mary");
        report.setAge(80);
        report.setCreatTime(new Date());
        System.out.println(report.toString());

        //当Report的参数很多,重复属性又很大时,先clone,再修改差异值,就节约很多时间。
        Report report1 = (Report) report.clone();
        report1.setName("Tom");
        System.out.println(report1.toString());

        Report report2 = (Report) report.clone();
        System.out.println(report == report2);

        //浅拷贝的弊端:属性对象指向堆中同一对象,一个修改,全部修改。
        report2.getCreatTime().setTime(0);
        System.out.println("report1:"+report1.toString());
        System.out.println("report2:"+report2.toString());

    }
}

@Data
class Report implements Cloneable {
    private int id;
    private String name;
    private int age;
    private Date creatTime;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

输出结果

Report(id=1, name=mary, age=80, creatTime=Thu Sep 24 11:37:38 CST 2020)
Report(id=1, name=Tom, age=80, creatTime=Thu Sep 24 11:37:38 CST 2020)
false
report1:Report(id=1, name=Tom, age=80, creatTime=Thu Jan 01 08:00:00 CST 1970)
report2:Report(id=1, name=mary, age=80, creatTime=Thu Jan 01 08:00:00 CST 1970)

Process finished with exit code 0
report2.getCreatTime().setTime(0);只是设置了report2的时间,但是report1的时间也被修改了。
属性对象指向堆中同一对象,一个修改,全部修改。下图的Object C 就是Date

解决这个问题,就有了深克隆,在克隆时,对于时间也克隆一份。

class Report implements Cloneable {
    private int id;
    private String name;
    private int age;
    private Date creatTime;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Report report = (Report) super.clone();
        //克隆一份date 让克隆前后的两个Date对象指向不同的堆中对象
        Date date = (Date) report.getCreatTime().clone();
        report.setCreatTime(date);
        return report;
    }
}

再次运行的结果

Report(id=1, name=mary, age=80, creatTime=Thu Sep 24 11:51:05 CST 2020)
Report(id=1, name=Tom, age=80, creatTime=Thu Sep 24 11:51:05 CST 2020)
false
report1:Report(id=1, name=Tom, age=80, creatTime=Thu Sep 24 11:51:05 CST 2020)
report2:Report(id=1, name=mary, age=80, creatTime=Thu Jan 01 08:00:00 CST 1970)

Process finished with exit code 0

可以看出report1和report2的时间不一样了。深拷贝成功。下面原理图

关于深克隆,以上实现方式,对于属性的增减,也很麻烦,有个一劳永逸且快速的方法,序列化的方式深克隆,文件流写入内存,请勿写到文件中。

 //深拷贝 方式2 用序列化 推荐使用.
    @Override
    protected Object clone() throws CloneNotSupportedException {

        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(out);
            oos.writeObject(this);//谁调用此clone方法,就序列化谁。
            oos.close();

            byte[] bb = out.toByteArray();
            InputStream is = new ByteArrayInputStream(bb);
            ObjectInputStream ois = new ObjectInputStream(is);
            Object o = ois.readObject();
            ois.close();
            return o;
        } catch (Exception e){
            throw  new RuntimeException(e);
        }
    }

如果你指定F://aa.txt  那其他环境无法运行,别人没有F盘,或者Linux执行等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值