03-JAVA设计模式-原型模式

原型模式

什么是原型模式

Java原型模式(Prototype Pattern)是一种创建型设计模式,其核心理念在于通过复制(克隆)已有的对象来创建新的对象,而不是通过构造函数来创建。
该模式可以显著提高对象创建的效率,特别是在需要频繁创建对象或对象创建过程较为复杂的场景下。

在原型模式中,原型对象作为基础对象,其他对象通过复制这个原型对象来创建新的实例。复制过程可以是浅克隆或深克隆。

  • 浅克隆创建一个新对象,新对象的属性和原对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
  • 深克隆则更为彻底,不仅创建新对象,而且属性中引用的其他对象也会被克隆,不再指向原有对象的内存地址。

注意:发生浅拷贝主要针对数据类型为引用类型。

使用场景及特点

  • 当通过new产生一个对象需要非常反锁的数据准备及访问权限时,则可以使用原型模式
  • 就是java中的克隆技术,以某个对象为原型,复制出新的对象。显然,新的对象具备原型对象的特点。
    • 优势:效率高(直接克隆,避免了重新执行构造过程的步骤)
  • 克隆类似于new,但是不同于new。new创建新的对象属性采用的是默认值,克隆对象的属性完全与原型对象相同,并且克隆出的新对象改变不会影响原型对象,然后再修改克隆对象的值。

原型模式实现

  • Cloneable接口和clone方法
  • 原型模式中实现起来最为困难的地方就是内存复制操作,然而在Java中提供了对象的clone()方法替我门做了绝大部分事情。

案例

使用原型模式,必须实现Cloneable接口,重写protected Object clone()方法

浅拷贝

Address.java

//地址
public class Address {
  private String city;

  public Address(String city) {
    this.city = city;
  }

  public void setCity(String city) {
    this.city = city;
  }

  @Override
  public String toString() {
    return "Address{" +
            "city='" + city + '\'' +
            '}';
  }
}

Person.java

// 浅拷贝
// 实现Cloneable接口 重写protected Object clone()方法
public class Person implements Cloneable{
  private String name;

  private Address address;

  public Person(String name, Address address) {
    this.name = name;
    this.address = address;
  }

  public Address getAddress() {
    return address;
  }

  public void setAddress(Address address) {
    this.address = address;
  }

  @Override
  protected Object clone() throws CloneNotSupportedException {
    return super.clone();   // 默认浅拷贝
  }

  @Override
  public String toString() {
    return "Person{" +
            "name='" + name + '\'' +
            ", address=" + address +
            '}';
  }
}

TestClient.java

public class TestClient {

    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person("张三",new Address("北京"));
        Person clone = (Person) person.clone();
        System.out.printf("浅拷贝-原型对象:%s%n",person);
        System.out.printf("浅拷贝-拷贝对象值:%s%n",clone);

        System.out.println("======修改原型对象-address======");
        person.getAddress().setCity("重庆");
        System.out.printf("浅拷贝-原型对象:%s%n",person);
        System.out.printf("浅拷贝-拷贝对象值:%s%n",clone);

        System.out.println("======修改拷贝对象-address======");
        clone.getAddress().setCity("广州");
        System.out.printf("浅拷贝-原型对象:%s%n",person);
        System.out.printf("浅拷贝-拷贝对象值:%s%n",clone);
    }
}

执行结果:

在这里插入图片描述

图解

在这里插入图片描述

浅拷贝时,当修改原型对象时,拷贝的对象引用仍然指向原型对象的引用,因此修改原型对象,会导致拷贝对象的值发生改变
修改拷贝对象的属性时,则会在堆内存中创建一个新的地址存储新设置的值,拷贝对象引用指向新的引用地址,但不会改变原型对象的引用地址。

深拷贝

Address.java 实现Cloneable接口,重新clone()

// 地址
public class Address implements Cloneable{
    private String city;

    public Address(String city) {
        this.city = city;
    }

    public void setCity(String city) {
        this.city = city;
    }

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

    @Override
    public String toString() {
        return "Address{" +
                "city='" + city + '\'' +
                '}';
    }
}

修改Person clone()方法

// 深拷贝
public class Person implements Cloneable{
    private String name;

    private Address address;

    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person clone = (Person) super.clone();
        clone.address = (Address) this.getAddress().clone();
        return clone;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", address=" + address +
                '}';
    }
}

TestClient2.java

public class TestClient2 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person("张三",new Address("北京"));
        Person clone = (Person) person.clone();
        System.out.printf("深拷贝-原型对象:%s%n",person);
        System.out.printf("深拷贝-拷贝对象值:%s%n",clone);

        System.out.println("======修改原型对象-address======");
        person.getAddress().setCity("重庆");
        System.out.printf("深拷贝-原型对象:%s%n",person);
        System.out.printf("深拷贝-拷贝对象值:%s%n",clone);

        System.out.println("======修改拷贝对象-address======");
        clone.getAddress().setCity("广州");
        System.out.printf("深拷贝-原型对象:%s%n",person);
        System.out.printf("深拷贝-拷贝对象值:%s%n",clone);
    }
}

执行结果:

在这里插入图片描述

图解

在这里插入图片描述

利用序列化和反序列化完成深克隆

通过序列化及反序列化实现深克隆必须实现Serializable接口
Person.java

public class Person implements Serializable {

  private String name;

  private Address address;

  public Person(String name, Address address) {
    this.name = name;
    this.address = address;
  }

  public Address getAddress() {
    return address;
  }

  public void setAddress(Address address) {
    this.address = address;
  }

  @Override
  public String toString() {
    return "Person{" +
            "name='" + name + '\'' +
            ", address=" + address +
            '}';
  }
}

Address.java

// 地址
public class Address implements Serializable {

    private String city;

    public Address(String city) {
        this.city = city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    @Override
    public String toString() {
        return "Address{" +
                "city='" + city + '\'' +
                '}';
    }
}

TestClient3.java

public class TestClient3 {
    public static void main(String[] args) throws CloneNotSupportedException, Exception {
        Person person = new Person("张三",new Address("北京"));
        // 通过序列化 反序列化实现深拷贝

        byte[] bytes = null;
        Person clone = null;

        // 序列化
        try( ByteArrayOutputStream baos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(baos);){
            oos.writeObject(person);
            bytes = baos.toByteArray();
        }

        // 反序列化
        try( ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
             ObjectInputStream ois = new ObjectInputStream(bais);){
            clone = (Person) ois.readObject();
        }

        System.out.printf("深拷贝-原型对象:%s%n",person);
        System.out.printf("深拷贝-拷贝对象值:%s%n",clone);

        System.out.println("======修改原型对象-address======");
        person.getAddress().setCity("重庆");
        System.out.printf("深拷贝-原型对象:%s%n",person);
        System.out.printf("深拷贝-拷贝对象值:%s%n",clone);

        System.out.println("======修改拷贝对象-address======");
        clone.getAddress().setCity("广州");
        System.out.printf("深拷贝-原型对象:%s%n",person);
        System.out.printf("深拷贝-拷贝对象值:%s%n",clone);
    }
}

执行结果:

在这里插入图片描述

gitee源码

git clone https://gitee.com/dchh/JavaStudyWorkSpaces.git

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Web3的智能合约:未来合约的新范式

随着区块链技术的不断成熟和发展,智能合约作为其核心应用之一,正逐渐成为数字经济中的重要组成部分,引领着未来合约的新趋势。Web3的智能合约代表了一种全新的合约形式,其特点和应用将在未来产生深远影响。 智能合约的基本原理 智…

React - 你知道props和state之间深层次的区别吗

难度级别:初级及以上 提问概率:60% 如果把React组件看做一个函数的话,props更像是外部传入的参数,而state更像是函数内部定义的变量。那么他们还有哪些更深层次的区别呢,我们来看一下。 首先说props,他是组件外部传入的参数,我们知道…

皮具5G智能制造工厂数字孪生可视化平台,推进企业数字化转型

皮具5G智能制造工厂数字孪生可视化平台,推进企业数字化转型。随着信息技术的快速发展,数字化转型已成为企业提升竞争力、实现可持续发展的关键路径。皮具行业,作为一个传统的手工制造业,正面临着巨大的市场变革和技术挑战。如何在…

07 spring-cloud-gateway 的路由相关

前言 我们这里 大致梳理一下 spring-cloud-gateway 路由的相关处理 spring-cloud 微服务组件中的网关 这里主要分为几个 步骤 路由规则怎么获取如何路由网关过滤器的处理如何转发请求道下游微服务组件 路由规则怎么获取? GatewayAutoConfiguration 中包含了 spring-clou…

华为手机 鸿蒙系统 或者安卓系统的百度网盘下载的文件保存在手机什么位置如何查看

华为手机 鸿蒙系统 或者安卓系统的百度网盘下载的文件保存在手机什么位置如何查看 连接电脑后一般在这里位置 计算机\Mate 20 Pro (UD)\内部存储\Download\BaiduNetdisk 也就是用usb(数据线,不是充电线,要四心的 )连接手机后,打…

JVM字节码与类加载——字节码指令集与解析

文章目录 1、概述1.1、字节码与数据类型1.2、指令分类 2、加载与存储指令2.1、局部变量入栈指令2.2、常量入栈指令2.3、出栈装入局部变量表指令 3、算术指令3.1、彻底理解i与i3.2、比较指令 4、类型转换指令4.1、宽化类型转换4.2、窄化类型转换 5、对象、数组的创建与访问指令5…

Leetcode 437. 路径总和 III

心路历程: 这道题递推并不难,但是有细节需要注意,主要就是区间可以不是根节点,以及结束不一定是叶子结点这两个限制。 其余的动态规划即可。 注意的点: 1、由于终点不一定是叶子结点,所以当递归的target…

css字体加粗实例

确定字体粗细的是font-weight属性&#xff1b; 它的number值可取100-900&#xff1b; 如果把属性设为normal&#xff0c;相当于number为400&#xff1b; 设为bold&#xff0c;相当于number为700&#xff1b; html<b>或<strong>跟bold效果一样&#xff1b; <!…

基于velero和minio实现k8s数据的备份

1.30部署minio rootk8s-harbor:/etc/kubeasz/clusters/k8s-cluster1# docker run \ -d --restartalways -p 9000:9000 -p 9090:9090 –name minio -v /data/minio/data:/data -e “MINIO_ROOT_USERadmin” -e “MINIO_ROOT_PASSWORD12345678” quay.io/minio/minio server…

java实现UDP数据交互

1、回显服务器 服务器端 import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketException;public class UDP_Server {private DatagramSocket socketnull;public UDP_Server(int port) throws SocketExcepti…

工地安全监测识别摄像机

工地安全监测识别摄像机是一种在建筑工地和施工现场广泛使用的智能监控设备&#xff0c;主要用于监测施工过程中可能出现的安全隐患和违规行为&#xff0c;以确保工地人员和设备的安全。通过高清摄像头、智能算法和远程监控系统的结合&#xff0c;该摄像机可以实时监测工地各个…

4.8作业

1、使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 将登录按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin"&#xff0c;密码是…

Qt | Q_PROPERTY属性和QVariant 类

一、属性基础 1、属性与数据成员相似,但是属性可使用 Qt 元对象系统的功能。他们的主要差别在于存取方式不相同,比如属性值通常使用读取函数(即函数名通常以 get 开始的函数)和设置函数(即函数名通常以 set 开始的函数)来存取其值,除此种方法外,Qt 还有其他方式存取属性值…

EditPlus来啦(免费使用!)

hello&#xff0c;我是小索奇 今天推荐一款编辑器&#xff0c;是索奇学习JavaSE时入手滴&#xff0c;非常好用哈&#xff0c;小索奇还是通过老杜-杜老师入手滴&#xff0c;相信很多人也是通过老杜认识嘞&#xff0c;来寻找破解版或者准备入手这个间接使用的编辑器~ EditPlus是…

Ubuntu22.04修改默认窗口系统为X11

Ubuntu22.04安装默认窗口系统为Wayland&#xff08;通过设置->关于可以看到&#xff09;。 一、用Ubuntu on Xorg会话登录 用户登录时&#xff0c;点“未列出”&#xff0c;输入用户名后&#xff0c;在登录界面底部的齿轮图标中&#xff0c;选择 "Ubuntu on Xorg&quo…

windows下使用ZLMediaKit-API+FFmpeg+opengl拉取解码播放流媒体

ZLMediaKit简介 ZLMediaKit是一个基于C11的高性能运营级流媒体服务框架&#xff0c;和SRS类似&#xff0c;功能强大&#xff0c;性能优异&#xff0c;提供多种支持多种协议(RTSP/RTMP/HLS/HTTP-FLV/WebSocket-FLV/GB28181/HTTP-TS/WebSocket-TS/HTTP-fMP4/WebSocket-fMP4/MP4/…

解决idea种maven依赖时明明有包,但是一直提示 Cannot resolve com.grandtech:gny-common:0.0.7

1、先看提示问题 &#xff0c;Cannot resolve com.grandtech:gny-common:0.0.7&#xff0c; 2、依赖我也是是没有问题 3、在maven库中的包也是要来的新的别人能运行的。但是放进去就是无法解析。 解决办法&#xff1a;在idea中直接&#xff0c;用mvn命令装载&#xff1a; ①…

设计模式浅析(十一) ·状态模式

设计模式浅析(十一) 状态模式 日常叨逼叨 java设计模式浅析&#xff0c;如果觉得对你有帮助&#xff0c;记得一键三连&#xff0c;谢谢各位观众老爷&#x1f601;&#x1f601; 状态模式 概念 状态模式 Java中的状态模式&#xff08;State Pattern&#xff09;是一种行为型…

Vue3中对v-md-editor编辑器的集成使用

效果展示&#xff1a; 首先安装需要的包 npm i kangc/v-md-editornext -S 在main.js中进行全局配置 import VMdEditor from kangc/v-md-editor/lib/codemirror-editor; import kangc/v-md-editor/lib/style/codemirror-editor.css; import githubTheme from kangc/v-md-ed…

学透Spring Boot — 005. 深入理解 Spring Boot Starter 依赖管理

前面的文章直观的展示了&#xff0c;使用Spring Boot 集成 Hibernate 和手动集成 Hibernate 之间差距。 一个比喻 工作中使用过Spring Boot一段时间后&#xff0c;我越来越感觉到Spring Boot Starter带来的便利性。 使用手动集成 Hibernate&#xff0c; 就像去电脑城配电脑&…