设计模式--原型模式

news2024/9/22 3:22:37

目录

基本介绍

传统方式克隆

原型模式改进

浅拷贝和深拷贝

浅拷贝的介绍

深拷贝的介绍

原型模式的注意事项和细节


基本介绍

(1) 原型模式(prototype模式): 用原型实例指定创建对象的种类 并且通过拷贝这些原型 创建新的对象

(2) 原型模式是一种创建型设计模式 允许一个对象再创建另一个可定制的对象 而不需要知道如何创建的细节

(3) 工作原理: 通过将一个原型对象传给那个要发动创建的对象 这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建 即对象.clone()

传统方式克隆

(1) 优点是简单易操作 比较好理解

(2) 在创建新的对象时 总是需要重新获取原始对象的属性 如果创建的对象比较复杂时 效率较低

(3) 总是需要重新初始化对象 而不是动态地获得对象运行时的状态 不够灵活

(4)改进思路分析

    java中Object类是所有类的基类 Object类提供了一个clone()方法 该方法可以将一个java对象复制一份 但是需要实现clone的java类必须要实现一个接口Cloneable 该接口表示该类能够复制且具有复制的能力-->原型模式

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Monkery {
    private String name;
    private Integer age;
    private String color;

}

测试结果:

 

原型模式改进

要克隆的实例实现Cloneable接口并实现默认的clone方法

@Data
@NoArgsConstructor
@AllArgsConstructor
public class MonkeyClone implements Cloneable{

    private String name;
    private Integer age;
    private String color;
    //克隆该实例 使用默认的clone方法实现
    @Override
    protected Object clone() {
        MonkeyClone monkeyClone = null;
        try {
            monkeyClone = (MonkeyClone)super.clone();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        return monkeyClone;
    }
}

 测试结果:

浅拷贝和深拷贝

浅拷贝的介绍

(1) 对于数据类型是基本数据类型的成员变量 浅拷贝会直接进行值传递 也就是将该属性值复制一份给新的对象

(2) 对于数据类型是引用数据类型的成员变量 比如说成员变量是某个数组 某个类的对象等 那么浅拷贝会进行引用传递 也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象 因为实际上两个对象的该成员变量都指向同一个实例 在这种情况下 在一个对象中修改该成员变量的话会影响其他对象的该成员变量值

(3) 前面的克隆monkey就是浅拷贝

(4) 浅拷贝是使用默认的clone()方法来实现  monkey=(MonkeyClone) super.clone();

为MonkeyClone 添加一个MonkeryClone类型的child属性 此时这个数据类型即为引用类型

@Data
@NoArgsConstructor
@AllArgsConstructor
public class MonkeyClone implements Cloneable{

    private String name;
    private Integer age;
    private String color;
    private MonkeyClone child;

    public MonkeyClone(String name, Integer age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    //克隆该实例 使用默认的clone方法实现
    @Override
    protected Object clone() {
        MonkeyClone monkeyClone = null;
        try {
            monkeyClone = (MonkeyClone)super.clone();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        return monkeyClone;
    }
}

我们接下来看引用数据类型的clone特性:

测试

 

我们这里可以看到,后面复制的monke它们的hashCode都是一致的,说明它们的内存地址指向的都是同一个地址

深拷贝的介绍

(1) 复制对象的所有基本数据类型的成员变量值

(2) 为所有引用数据类型的成员变量申请储存空间 并复制每个引用数据类型成员变量所引用的对象 直到该对象可达的所有对象 也就是说 对象进行深拷贝要对整个对象进行拷贝

(3) 深拷贝的实现方式1: 重写clone方法来实现深拷贝

(4) 深拷贝的实现方式2: 通过对象序列化来实现深拷贝

public class DeepCloneTarget implements Serializable,Cloneable {
    private String cloneName;
    private String cloneClass;

    public DeepCloneTarget(String cloneName, String cloneClass) {
        this.cloneName = cloneName;
        this.cloneClass = cloneClass;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
@Data
@Accessors(chain = true)
public class DeepProtoType implements Serializable,Cloneable {
     String name; //String 属性
     DeepCloneTarget deepCloneTarget; //引用类型

    public DeepProtoType() {
        super();
    }

    //深拷贝 方式1 使用clone方法


    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object deep = null;
        //这里完成对基本数据类型(属性)和String的克隆
        deep = super.clone();
        //对引用类型的属性 进行单独处理
        DeepProtoType deepProtoType =(DeepProtoType) deep;
        deepProtoType.deepCloneTarget = (DeepCloneTarget) deepCloneTarget.clone();
        return deepProtoType;
    }
}

方式二:

@Data
@Accessors(chain = true)
public class DeepProtoType implements Serializable,Cloneable {
     String name; //String 属性
     DeepCloneTarget deepCloneTarget; //引用类型

    public DeepProtoType() {
        super();
    }

    //深拷贝 方式1 使用clone方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object deep = null;
        //这里完成对基本数据类型(属性)和String的克隆
        deep = super.clone();
        //对引用类型的属性 进行单独处理
        DeepProtoType deepProtoType =(DeepProtoType) deep;
        deepProtoType.deepCloneTarget = (DeepCloneTarget) deepCloneTarget.clone();
        return deepProtoType;
    }

    //深拷贝 方式2 通过对象序列化实现(推荐)
    public Object deepClone(){
        //创建流对象
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        try{
            //序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this); //当前这个对象以对象流的方式输出

            //反序列化
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            DeepProtoType copyObj = (DeepProtoType) ois.readObject();
            return copyObj;

        }catch (Exception e){
            e.printStackTrace();
            return null;
        }finally {
            //关闭流
            try {
                bos.close();
                oos.close();
                ois.close();
                bis.close();
            }catch (Exception ee){
                System.out.println(ee.getMessage());
            }
        }
    }
}

测试

原型模式的注意事项和细节

(1) 创建新的对象比较复杂时 可以利用原型模式简化对象的创建过程 同时也能够提高效率

(2) 不用初始化对象 而是动态地获得对象运行时的状态

(3) 如果原始对象发生变化(增加或者减少属性) 其他克隆对象的也会发生相应的变化 无需修改代码

(4) 在实现深克隆的时候可能需要比较复杂的代码

(5) 缺点: 需要为每一个类配备一个克隆方法 这对全新的类来说不是很难 但对已有的类进行改造时 需要修改其源码 违背了ocp原则

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

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

相关文章

妙用Java 8中的 Function接口,消灭if...else

在开发过程中经常会使用if...else...进行判断抛出异常、分支处理等操作。这些if...else...充斥在代码中严重影响了代码代码的美观,这时我们可以利用Java 8的Function接口来消灭if...else...。 if (...){throw new RuntimeException("出现异常了")&#x…

全网详细解决1093 - You can‘t specify target table ‘xxx‘ for update in FROM clause的错误

文章目录 1. 复现错误2. 分析错误3. 解决错误 1. 复现错误 今天在工作时,接到一个新需求,就是将app_page_button表中的label_code字段修改为edit,条件如下: 只更新值为null的label_code 且以/edit/${id}结尾的option_value 首先…

基于微信小程序+爬虫制作一个表情包小程序

跟朋友聊天斗图失败气急败坏的我选择直接制作一个爬虫表情包小程序,从源头解决问题,从此再也不用担心在斗图中落入下风 精彩专栏持续更新↓↓↓ 微信小程序实战开发专栏 一、API1.1 项目创建1.2 图片爬虫帮助类1.3 测试窗体1.4 接口封装二、小程序2.1 项目创建2.2 页面设计2.…

css 实现太极效果

目录 一、简述二、太极效果制作 一、简述 本次主要介绍::after,::before,box-shadow这三个属性。 ::after,::before这两个是伪类选择器,box-shaow是用来设置元素的阴影效果 before:向选定的元素前插入内容 after:向选定的元素后插…

关于在线CAD编辑的解决方案思考

基于ODA的VisualizeJs库的能力 ODA官网的OpenCloud提供了在线浏览CAD图纸的能力(ODA自身也不支持直接在线解析Dwg,而是通过ODA提供的WebTools里面的FileConverter的能力将dwg图纸转换为VSF格式(CAD的一种二三维格式,在AutoCAD中也有一种类似的ForgeView…

chatGPT衣食住行10种场景系列教程(01)使用chatGPT设计发型、P图变漂亮~真帅哈哈哈~

导读 时隔5个多月,chatGPT可谓是一日千里,越演越火,携带着AIGC行业一起飞了起来,那么在短短5个月当中有那些值得我们关注的事件?有那些好玩的场景?以及有那些chatGPT好用的工具?本文都将一一告…

neo4j数据库的安装及使用

一、安装neo4j 安装neo4j数据库,需要先安装jdk,jdk版本不能太低,不然运行neo4j的时候会报错。 我下载的是jdk11,以前已经下载过了,这里不再进行演示,下载jdk11的教程应该挺多的,自己搜一个吧 …

nodejs+vue美容院预约管理系统springboot+java+python

本课题将根据用户类型大致划分为管理员模块和美容师模块和用户模块,开发语言拟采用目前比较 语言 node.js 框架:Express 前端:Vue.js 数据库:mysql 数据库工具:Navicat 开发软件:VScode ,界面采用vue前端框…

jsp+servlet教材预定系统mysql

目 录 一、引言 6 (一) 课题目的及意义 6 1、课题目的 6 2、课题研究意义 6 (二) 国内外研究现状 6 1、国外研究现状 6 2、国内研究现状 7 (三) 研究方法及设计思路 7 1、研究方法 7 2、设计思路 8 二、需求分析与可行性分析 9 (一) 需求分析…

源码:LeakCanary

一、介绍 自动检测内存泄漏的检查工具 二、使用 debugImplementation com.squareup.leakcanary:leakcanary-android:2.5debugImplementation只在debug模式的编译和最终的debug apk打包时有效 Memory Profiler 使用步骤 生成的内存泄漏快照 会放在sdcard/Download/leakcanar…

Node【Global全局对象】之【URL】

文章目录 🌟前言🌟URL🌟URL组成部分🌟URL 类🌟url.href🌟url.pathname🌟url.port🌟url.protocol🌟url.search🌟url.searchParams🌟url.hash&#…

DAY829

学习目标:成就上瘾,学到欲罢不能 4月(复习完高数18讲内容,背诵21篇短文,熟词僻义300词基础词) 学习内容: 暴力英语:背单词150个,背《死亡诗社》经典语段,抄写…

【web前端开发】CSS定位

文章目录 1.定位介绍2.定位的方式2.1 相对定位2.2 绝对定位2.2.1 子绝父相 2.3 固定定位 3. 元素的层级关系4. 总结 1.定位介绍 定位有两个作用: 1.可以解决盒子和盒子之间的层叠问题 (定位之后元素层级最高,可以层叠在其它盒子上面) 2.可以让盒子始终固定在屏幕中的某个位置 …

shell呈现数据

shell脚本编程系列 理解输入和输出 目前为止了解了两种显示脚本输出的方法:在显示器屏幕上显示输出,将输出重定向到文件中,这两种方法将数据输出全部显示出来,要么什么都不显示,但有时一部分数据显示屏幕上&#xff0…

Android---启动页+闪屏页

目录 启动页 闪屏页 启动页 app 在进入首页面的过程中,都会线加载一张图片然后再进入闪屏页。这样,可以给用户很好的体验。 作用:避免加载白屏页面,进行业务的预处理(网络检测、数据预加载...) 界面组成…

基于Pyqt5快速构建应用程序详细教程

一、介绍 图形用户界面,更广为人知的名称是 GUI,是当今大多数个人计算机的一个特征。 它为不同计算技能水平的用户提供了直观的体验。 尽管 GUI 应用程序可能会使用更多资源,但由于其点击式特性,它们通常对用户友好。 PyQt 是可用…

最小生成树|二分图

最小生成树跟边的正负没有任何关系。 最小生成树 朴素Prime 该算法和Dijkstr算法很像。 先把所有距离初始化为正无穷 进行n次迭代 找到不在集合(集合指当前的生成树)当中的点,s数组表示当前已经在连通块(生成树)中的所…

vue-simple-uploader在VUE3中分片上传大文件

vue-simple-uploader是一个优秀的大文件分片上传组件,在vue2里面工作一切正常,但是在vue3里面却发现了一些问题: (1)在element-plus的el-dialog里面渲染失败; (2)上传进度条不能正…

由浅入深详解四种分布式锁

在多线程环境下,为了保证数据的线程安全,锁保证同一时刻,只有一个可以访问和更新共享数据。在单机系统我们可以使用synchronized锁或者Lock锁保证线程安全。synchronized锁是Java提供的一种内置锁,在单个JVM进程中提供线程之间的锁…

信息系统项目管理师,第四版应该如何应对

一、 改版情况。 2023年3月,新版教材起售。 2023年4月4日,官网宣布本次考试第三版第四版兼顾使用。 以历年的考试时间来看,一般这次考试是在 5月27日、28日附近。 接下来只有一个月左右的时间了。给大家聊聊面对现在这个情况如何备考。 …