设计模式之原型模式(Prototype)

news2024/11/24 20:15:12

原型模式

如果已经有一个对象了,你想创建一个对象,而且对象里面的属性和已经存在的对象的属性差不多,就可以使用clone方法
克隆一个出来
在这里插入图片描述

实现原型模式需要实现标记型接口Cloneable -->标记型接口 : 里面没有需要实现的方法(空接口)
一般会重写clone方法 --> 如果只是重新clone方法,而没有实现Cloneable接口,调用时会报异常
一般用于一个对象的属性以及确定,需要产生很多相同或大部分属性相同的对象的时候
需要区分深克隆和浅克隆

java自带,Object类里面有个Object.clone()。也称为克隆模式
clone方法是protected native方法 C++实现 只能子类调用

浅克隆:
Object的clone,是在内存里面重新创建一个对象,copy过来原来对象的属性,如果是基本数据类型,拷贝的是值过去,
如果是引用数据类型,拷贝的是对象的内存地址,指向的是同一个对象,互相有影响
有没有方法把引用的对象也拷贝一份呢? --> 深克隆

/**
 * 浅克隆
 */

public class Test {
    public static void main(String[] args) throws Exception {
        Person p1 = new Person();
        // 克隆
        Person p2 = (Person)p1.clone();
        // 基本数据类型,值直接copy过来
        System.out.println(p2.age + " " + p2.score);
        System.out.println(p2.loc);
        // 引用数据类型,copy的是内存地址,指向的是同一个对象,所以相等
        System.out.println(p1.loc == p2.loc); // true
        // 如果p1对象的loc改变了,p2的loc也会改变
        p1.loc.street = "sh";
        System.out.println(p2.loc); // sh

    }
}

// 实现Cloneable接口
class Person implements Cloneable {
    int age = 8;
    int score = 100;

    Location loc = new Location("bj", 22);
    // 实现clone方法
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

class Location {
    String street;
    int roomNo;

    @Override
    public String toString() {
        return "Location{" +
                "street='" + street + '\'' +
                ", roomNo=" + roomNo +
                '}';
    }

    public Location(String street, int roomNo) {
        this.street = street;
        this.roomNo = roomNo;
    }
}

深克隆:
引用的对象Location也实现Cloneable接口以及clone方法,在clone Person对象的时候将原来对象的loc也clone一份出来,
然后新clone出来 的对象的loc引用指向clone处理的loc

/**
 * 深克隆的处理
 */
public class Test {
    public static void main(String[] args) throws Exception {
        Person p1 = new Person();
        Person p2 = (Person)p1.clone();
        System.out.println(p2.age + " " + p2.score); // 8 100
        System.out.println(p2.loc);
        // 不是同一个对象了
        System.out.println(p1.loc == p2.loc); // false
        p1.loc.street = "sh";
        // 改变p1的loc不好影响p2
        System.out.println(p2.loc); // bj
    }
}

class Person implements Cloneable {
    int age = 8;
    int score = 100;

    Location loc = new Location("bj", 22);
    @Override
    public Object clone() throws CloneNotSupportedException {
        // clone一份新的对象出来
        Person p = (Person)super.clone();
        // 将原来的loc,也clone一份出来,新对象的loc指针指向clone处理的loc对象
        p.loc = (Location)loc.clone();
        return p;
    }
}
// 被引用的对象实现Cloneable接口以及clone方法
class Location implements Cloneable {
    String street;
    int roomNo;

    @Override
    public String toString() {
        return "Location{" +
                "street='" + street + '\'' +
                ", roomNo=" + roomNo +
                '}';
    }

    public Location(String street, int roomNo) {
        this.street = street;
        this.roomNo = roomNo;
    }

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

引用数据类型,在深克隆的时候,是需要被克隆一份的,上面的String也是引用数据类型,clone的时候也需要将它克隆一份吗?
不需要。
String类型放在了常量池里面,比如说第一个Person对象里面的String指向的是常量池里面的"bj",clone出来的对象也是指向的常量池里面的"bj",
如果第一个Person对象里面的String变成了"sh",是不会影响第二个对象的,因为只是第一个对象里面的String指向了常量池里面的"sh",被克隆出来
的对象还是指向的"bj"。

/**
 * String需要进一步深克隆吗?
 */
public class Test {
    public static void main(String[] args) throws Exception {
        Person p1 = new Person();
        Person p2 = (Person)p1.clone();
        System.out.println(p2.age + " " + p2.score);
        System.out.println(p2.loc);

        System.out.println(p1.loc == p2.loc); // false
        p1.loc.street = "sh";
        System.out.println(p2.loc);

        p1.loc.street.replace("sh", "sz");
        // 改变p1里面的string,不好影响p2
        System.out.println(p2.loc.street); // bj
    }
}

class Person implements Cloneable {
    int age = 8;
    int score = 100;

    Location loc = new Location("bj", 22);
    @Override
    public Object clone() throws CloneNotSupportedException {
        Person p = (Person)super.clone();
        p.loc = (Location)loc.clone();
        return p;
    }
}

class Location implements Cloneable {
    String street;
    int roomNo;

    @Override
    public String toString() {
        return "Location{" +
                "street='" + street + '\'' +
                ", roomNo=" + roomNo +
                '}';
    }

    public Location(String street, int roomNo) {
        this.street = street;
        this.roomNo = roomNo;
    }

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

下面的例子中,String用的是StringBuilder,Person 1和Person 2里面的String都是指向的同一个StringBuilder,所以
当Person 1的String改变之后,Person 2的String也会改变。
怎么解决? --> 深克隆的时候,也需要把StringBuilder克隆一份

/**
 * String需要进一步深克隆吗?
 */
public class Test {
    public static void main(String[] args) throws Exception {
        Person p1 = new Person();
        Person p2 = (Person)p1.clone();
        // loc 经过clone之后指向的不是同一个对象
        System.out.println("p1.loc == p2.loc? " + (p1.loc == p2.loc)); // false
        // p1和p2里面的String指向的是同一个StringBuilder,所以当p1里面的String改变的时候,
        // p2的也会改变
        p1.loc.street.reverse();
        System.out.println(p2.loc.street); // jb
    }
}

class Person implements Cloneable {
    int age = 8;
    int score = 100;

    Location loc = new Location(new StringBuilder("bj"), 22);
    @Override
    public Object clone() throws CloneNotSupportedException {
        Person p = (Person)super.clone();
        p.loc = (Location)loc.clone();
        return p;
    }
}

class Location implements Cloneable {
    StringBuilder street;
    int roomNo;

    @Override
    public String toString() {
        return "Location{" +
                "street='" + street + '\'' +
                ", roomNo=" + roomNo +
                '}';
    }

    public Location(StringBuilder street, int roomNo) {
        this.street = street;
        this.roomNo = roomNo;
    }

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

深克隆用的少,面试也问的少,了解就行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1202850.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

双十一钜惠!三门不可多得的HarmonyOS学习教程

今年双十一,各大商城优惠不断。这里介绍三门不可多得的HarmonyOS学习教程,都有非常大的折扣优惠。 《鸿蒙HarmonyOS手机应用开发实战》 《鸿蒙HarmonyOS手机应用开发实战》是由清华大学出版社出版的。 目前当当是“7.56折”:http://produc…

照片放大软件 Topaz Gigapixel AI mac中文版简介

Topaz Gigapixel AI mac是一款使用人工智能功能扩展图像的桌面应用程序,同时添加自然细节以获得惊人的效果。使用深度学习技术,A.I.Gigapixel™可以放大图像并填写其他调整大小的产品遗漏的细节,使用A.I.Gigapixel™,您可以裁剪照…

Vatee万腾外汇数字化策略:Vatee科技决策力的未来引领

在外汇市场,Vatee万腾通过其前瞻性的外汇数字化策略,正引领着科技决策的未来。这一数字化策略的崭新愿景为投资者提供了更智慧、更高效的外汇投资体验,成为科技决策领域的翘楚。 Vatee万腾的外汇数字化策略是科技决策力未来引领的典范。通过运…

14.求n!和1!+2!+...+20!和2^1+2^2+……++2^20和2^1+2^3+……++2^19

文章目录 前言一、题目描述 二、题目分析 三、解题 程序运行代码 四、举一反三一、题目描述:求1!2!...20! 二、题目分析 三、解题 程序运行代码1程序运行代码2 一、题目描述:求求2^1^2^2^……2^20^二、解题 程序运行代码 一、题目…

将ChatGPT集成在AR中,Snap玩出了新花样!

著名社交媒体平台Snap在官网宣布,在最新的AR开发平台Lens Studio 5.0版本中,集成ChatGPT功能。 在ChatGPT的帮助下,开发人员可以创建更多有趣、科普、对话、创意的Snapchat镜头,例如,通过ChatGPT创建无限测验和随机生…

燃气管网监测系统|全面保障燃气安全

根据新华日报的报道,2023年上半年,我国共发生了294起燃气事故,造成了57人死亡和190人受伤,燃气事故的发生原因有很多,其中涉及到燃气泄漏、设备故障等因素。因此,加强燃气安全管理,提高城市的安…

祝贺莱佛士学生获得SDC国际设计大赛新加坡赛区冠军

染色师和调色师协会国际设计大赛(SDC International Design Competition,简称SDC国际设计大赛)由英国染色家协会(Society of Dyers and Colourists,简称SDC)举办。 SDC成立于1884年,是国际上最…

基于 PostgreSQL 构建 AI 电商产品图片相似度搜索方案

在这篇文章中,将介绍如何基于向量数据库,构建一个电商产品图片目录的向量相似度查询解决方案。我们将通过 Amazon SageMaker、pgvector 向量数据库扩展插件、小型语言模型助力 AI 图片搜索能力,从而在产品目录中查找到最符合条件的产品&#…

证明串口是好的

前提:客户返回来一个pad,说串口不好用,售后让研发确定一下串口好不好用。 pad的串口是usb口(不知道这样说对不对),然后就一个“usb--9针”的线。 要确定串口好不好,首先要从电脑发数据给pad&a…

【PyTorch教程】如何使用PyTorch分布式并行模块DistributedDataParallel(DDP)进行多卡训练

本期目录 1. 导入核心库2. 初始化分布式进程组3. 包装模型4. 分发输入数据5. 保存模型参数6. 运行分布式训练7. DDP完整训练代码 本章的重点是学习如何使用 PyTorch 中的 Distributed Data Parallel (DDP) 库进行高效的分布式并行训练。以提高模型的训练速度。 1. 导入核心库 D…

双十一电视盒子哪个牌子好?测评工作室整理口碑电视盒子排名

在挑选电视盒子的时候,新手朋友们不知道从何下手,最近很多粉丝评论想要我们分享双11电视盒子推荐,于是我们根据用户的评价整理了目前口碑最好的电视盒子排名,给不懂电视盒子哪个牌子好的朋友们做个参考。 TOP 1、泰捷WEBOX WE40S电…

【python自动化】Playwright基础教程(五)事件操作②悬停输入清除精讲

【python自动化】Playwright基础教程(五)事件操作②悬停&输入&清除精讲 本章目录 文章目录 【python自动化】Playwright基础教程(五)事件操作②悬停&输入&清除精讲鼠标悬停 - hover鼠标悬停实战 输入内容 - fill输入内容实战清空内容实战 输入内容 - type模拟…

stm32超声波测距不准的解决方法(STM32 delay_us()产生1us)及stm32智能小车超声波测距代码(C语言版本)

首先要说明一下原理:使用stm32无法准确产生1us的时间,但是超声波测距一定要依赖时间,时间不准,距离一定不准,这是要肯定的,但是在不准确的情况下,要测量一个比较准确的时间,那么只能…

内网穿透的应用-如何使用CFImagehost搭建简洁易用的私人图床并公网访问

文章目录 1.前言2. CFImagehost网站搭建2.1 CFImagehost下载和安装2.2 CFImagehost网页测试2.3 cpolar的安装和注册 3.本地网页发布3.1 Cpolar临时数据隧道3.2 Cpolar稳定隧道(云端设置)3.3.Cpolar稳定隧道(本地设置) 4.公网访问测…

北斗卫星为油气管道安全保障提供可靠技术支持

北斗卫星为油气管道安全保障提供可靠技术支持 随着现代社会对能源需求的不断增长,油气管道成为了能源输送的重要通道。然而,油气管道的安全风险也日益凸显。为了及时掌握油气管道的运行状态并有效地监测其安全状况,北斗卫星技术为油气管道监测…

VMware 虚拟机启动后自动重启电脑 问题的2个解决办法

我遇到的问题: vm配置好了新的虚拟机,不过点击启动虚拟机的时候电脑自动重启。无线点击启动、无限重启! 如有帮助 请点赞收藏关注我!谢谢啦 如有转载请注明出处! 我的解决办法: 1编辑虚拟机设置 硬件选项…

解决npm报错Error: error:0308010C:digital envelope routines::unsupported

解决npm报错Error: error:0308010C:digital envelope routines::unsupported。 解决办法;终端执行以下命令(windows): set NODE_OPTIONS--openssl-legacy-provider然后再执行 npm命令成功:

阿里云服务器白嫖还是选99元特价主机?

阿里云服务器0元到手攻略,咱别0元了,花点钱吧,99元行吗?不行也有0元的,一会阿腾云atengyun.com给大家细说。先说99元即可购买一台阿里云服务器,2核2G配置、3M固定带宽、40G系统盘,第二年续费还是…

印刷包装服务预约小程序的作用是什么

印刷包装厂家非常多,其主要服务为名片印刷、礼品纸袋定制、画册宣传单印刷等,这些服务对大多数企业都有很高的需求,同时具备批量、长期合作属性,同时具备跨区域合作性,所以品牌可扩展度高。 但高需求的同时&#xff0…

【机器学习】K近邻算法:原理、实例应用(红酒分类预测)

案例简介:有178个红酒样本,每一款红酒含有13项特征参数,如镁、脯氨酸含量,红酒根据这些特征参数被分成3类。要求是任意输入一组红酒的特征参数,模型需预测出该红酒属于哪一类。 1. K近邻算法介绍 1.1 算法原理 原理&a…