原型模式 与 建造者模式(2)

简介: 原型模式 与 建造者模式(2)

测试代码


public class Client {
    public static void main(String[] args) {
        //创建原型对象
        ConcretePrototype prototype = new ConcretePrototype();
        prototype.setAge(18);
        prototype.setName("Tom");
        System.out.println(prototype);
        //拷贝原型对象
        ConcretePrototype cloneType = prototype.clone();
        System.out.println(cloneType);
    }
}


运行结果:


image.png


在实际编码中,我们一般不会浪费这样的体力劳动,JDK已经帮我们实现了一个现成的API,我们只需要实现Cloneable接口即可。来改造一下代码,修改ConcretePrototype类:


@Data
public class ConcretePrototype implements Cloneable {
    private int age;
    private String name;
    private List<String> hobbies;
    @Override
    public ConcretePrototype clone() {
        try {
            return (ConcretePrototype)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
    @Override
    public String toString() {
        return "ConcretePrototype{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", hobbies=" + hobbies +
                '}';
    }
}


写一个测试用例


public class Client {
    public static void main(String[] args) {
        //创建原型对象
        ConcretePrototype prototype = new ConcretePrototype();
        prototype.setAge(18);
        prototype.setName("Tom");
        List<String> hobbies = new ArrayList<String>();
        hobbies.add("书法");
        hobbies.add("美术");
        prototype.setHobbies(hobbies);
        //拷贝原型对象
        ConcretePrototype cloneType = prototype.clone();
        cloneType.getHobbies().add("技术控");
        System.out.println("原型对象:" + prototype);
        System.out.println("克隆对象:" + cloneType);
        System.out.println(prototype == cloneType);
        System.out.println("原型对象的爱好:" + prototype.getHobbies());
        System.out.println("克隆对象的爱好:" + cloneType.getHobbies());
        System.out.println(prototype.getHobbies() == cloneType.getHobbies());
    }
}


运行结果


image.png


我们给复制后的克隆对象新增一项爱好,发现原型对象也发生了变化,这显然不符合我们的预期。因为我们希望克隆出来的对象应该和原型对象是两个独立的对象,不应该再有联系了。从测试结果分析来看,应该是hobies共用了一个内存地址,意味着复制的不是值,而是引用的地址。这样的话,如果我们修改的是一个对象中的属性值,prototype和cloneType的hobbies值都会改变。这就是我们常说的浅克隆。只是完整复制了值类型数据,没有复制引用对象。换言之,所有的引用对象仍然指向原来的对象,显然不是我们想要的结果。下面我们引入深克隆继续改造。


使用序列化实现深度克隆


在上面的基础上,我们继续改造,来看代码,增加一个deepClone()方法:


@Data
public class ConcretePrototype implements Cloneable,Serializable {
    private int age;
    private String name;
    private List<String> hobbies;
    @Override
    public ConcretePrototype clone() {
        try {
            return (ConcretePrototype)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
    public ConcretePrototype deepCloneHobbies(){
        try {
            ConcretePrototype result = (ConcretePrototype)super.clone();
            result.hobbies = (List)((ArrayList)result.hobbies).clone();
            return result;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
    public ConcretePrototype deepClone(){
        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 (ConcretePrototype)ois.readObject();
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
    @Override
    public String toString() {
        return "ConcretePrototype{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", hobbies=" + hobbies +
                '}';
    }
}


测试代码


public class Client {
    public static void main(String[] args) {
        //创建原型对象
        ConcretePrototype prototype = new ConcretePrototype();
        prototype.setAge(18);
        prototype.setName("Tom");
        List<String> hobbies = new ArrayList<String>();
        hobbies.add("书法");
        hobbies.add("美术");
        prototype.setHobbies(hobbies);
        //拷贝原型对象
        ConcretePrototype cloneType = prototype.deepCloneHobbies();
        cloneType.getHobbies().add("技术控");
        System.out.println("原型对象:" + prototype);
        System.out.println("克隆对象:" + cloneType);
        System.out.println(prototype == cloneType);
        System.out.println("原型对象的爱好:" + prototype.getHobbies());
        System.out.println("克隆对象的爱好:" + cloneType.getHobbies());
        System.out.println(prototype.getHobbies() == cloneType.getHobbies());
    }
}
目录
相关文章
|
安全 NoSQL Java
SpringSecurity原理简述(上)
SpringSecurity原理简述
283 2
|
机器学习/深度学习 数据可视化 数据挖掘
探索大数据时代的关键技术:数据挖掘、可视化和数据仓库
探索大数据时代的关键技术:数据挖掘、可视化和数据仓库
1226 0
|
10月前
|
JSON 前端开发 安全
WebSocket调试工具深度对比:Postman与Apipost功能实测解析
如果你在寻找既能搞定WebSocket调试,又能完美管理文档的工具,不妨试试Apipos!
368 1
|
Java API C++
Java JNI开发时常用数据类型与C++中数据类型转换
Java JNI开发时常用数据类型与C++中数据类型转换
581 0
|
机器学习/深度学习 人工智能 安全
2024年软件开发新趋势
【10月更文挑战第1天】2024年的软件开发领域正迎来诸多革新趋势。本篇文章深入探讨了这些变化,包括人工智能与机器学习的深度集成、区块链技术的应用、多运行时微服务的兴起,以及AR/VR技术在各行业的广泛采用。同时,网络安全成为焦点,从被动防御转向主动防护,如DevSecOps和零信任架构的普及。此外,文章还强调了可持续软件开发的重要性,提倡绿色计算以应对日益严峻的环境挑战。
|
传感器 机器学习/深度学习 算法
Isaac Sim教程01 Isaac Sim介绍
这篇文章是Isaac Sim的入门教程,介绍了NVIDIA Omniverse平台上的Isaac Sim机器人仿真工具包。内容包括Isaac Sim的背景、特点、应用场景、架构和工作流程,以及近期的更新情况。Isaac Sim支持物理精确的仿真和合成数据集的创建,与ROS/ROS2兼容,并能模拟多种传感器数据,适用于机器人导航、操作应用、计算机视觉研究和数据集生成等多种场景。
2195 2
Isaac Sim教程01 Isaac Sim介绍
|
存储 监控 数据库
InfluxDB数据备份与恢复策略
【4月更文挑战第30天】本文介绍了InfluxDB的时间序列数据备份与恢复策略。备份策略包括定期快照备份、增量备份(借助外部工具如rsync)及备份验证。恢复策略涉及从快照和备份验证环境恢复数据,强调了恢复过程中的注意事项,如关闭写入操作和数据一致性。实施这些策略能有效保障InfluxDB数据的安全性和可用性。
1077 0
|
Linux 网络安全 数据安全/隐私保护
CentOS 7安装配置vsftp并搭建FTP(一)
CentOS 7安装配置vsftp并搭建FTP(一)
24897 0
CentOS 7安装配置vsftp并搭建FTP(一)
idea创建Package时出现包名累加,而不是树形结构解决方法
idea创建Package时出现包名累加,而不是树形结构解决方法
320 0
|
JSON 数据处理 数据格式
yolov8训练自己的数据集以及权重转化为.engine格式(超详细)
yolov8训练自己的数据集以及权重转化为.engine格式(超详细)
1543 0