Java设计模式 | 原型模式

news2024/11/23 22:10:21

是什么

用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。
该模式的核⼼思想是基于现有的对象创建新的对象,⽽不是从头开始创建。

结构

  • 抽象原型接口:声明一个克隆自身的方法clone()
  • 具体原型类:实现抽象原型接口的clone()方法,复制当前对象并返回一个新对象
  • 访问类:使用具体原型类中的clone()方法来复制出新的对象

实现

类图:
image.png

Java中的Object类中提供了clone()方法来实现浅克隆。 Cloneable 接口是上面的类图中的抽象原型类,而实现了Cloneable接口的子实现类就是具体的原型类。代码如下:

具体原型类(Realizetype):

public class Realizetype implements Cloneable {

    public Realizetype() {
        System.out.println("具体原型对象创建成功!");
    }

    @Override
    protected Realizetype clone() throws CloneNotSupportedException {
        System.out.println("具体原型复制成功!");
        return (Realizetype) super.clone();
    }
}

访问测试类:

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        // 创建一个原型类对象
        Realizetype realizetype = new Realizetype();

        // 调用原型类中的clone()方法进行对象克隆
        Realizetype cloneRealizetype = realizetype.clone();

        System.out.println("原型类对象的地址:" + realizetype);
        System.out.println("克隆出来的对象的地址:" + cloneRealizetype);
        System.out.println("原型类对象和克隆出来的对象是否相同:" + (realizetype == cloneRealizetype));
    }
}

结果:

具体原型对象创建成功!
具体原型复制成功!
原型类对象的地址:com.jmd.prototype.demo.Realizetype@1b6d3586
克隆出来的对象的地址:com.jmd.prototype.demo.Realizetype@4554617c
原型类对象和克隆出来的对象是否相同:false

浅克隆&深克隆

浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址;
深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

案例

使用原型模式生成“三好学生”奖状
同一学校的“三好学生”奖状除了获奖人不同以外,其他都相同。可以使用原型模式复制多个奖状,再修改姓名即可。
类图:
image.png

具体原型类:

public class Citation implements Cloneable {

    // 三好学生姓名
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

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

    public void show() {
        System.out.println(name + "同学:在2024学年第一学期中表现优秀,被评为三好学生。特发此状!");
    }
}

访问类(测试):

public class CitationTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        // 1 创建原型对象
        Citation citation = new Citation();

        // 2 克隆奖状对象
        Citation citation1 = citation.clone();
        citation.setName("张三");
        citation1.setName("李四");

        // 3 调用show()方法
        citation.show();
        citation1.show();
    }
}

结果:

张三同学:在2024学年第一学期中表现优秀,被评为三好学生。特发此状!
李四同学:在2024学年第一学期中表现优秀,被评为三好学生。特发此状!

总结:
相比于直接实例化对象,通过原型模式复制当前对象可以减少资源消耗,提高性能,尤其在对象的创建过程复杂或对象的创建代价较大的情况下。当需要频繁创建相似对象,并且可以通过克隆避免重复初始化工作的场景时,可以考虑使用原型模式,在克隆对象时还可以动态的添加或删除原型对象的属性,创造出相似但不完全相同的对象,提高了灵活性。

但是使用原型模式也需要考虑:如果对象内部状态包含了引用类型的成员变量,那么实现深拷贝就会变得较为复杂,需要考虑引用类型对象的克隆问题。

使用场景

  • 对象的创建非常复杂
  • 性能和安全要求较高

扩展(实现深克隆)

将上面案例中Citation类中的name属性修改为Student类型的的属性。
学生类:

public class Student {

    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

奖状类:

public class Citation implements Cloneable {

    private Student student;

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

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

    public void show() {
        System.out.println(student.getName() + "同学:在2024学年第一学期中表现优秀,被评为三好学生。特发此状!");
    }
}

测试类:

public class CitationTest2 {
    public static void main(String[] args) throws CloneNotSupportedException {
        // 创建原型对象
        Citation citation = new Citation();
        Student student = new Student("张三", 18);
        citation.setStudent(student);

        // 复制奖状
        Citation citation1 = citation.clone();

        // 获取citation1奖状所属学生对象
        Student student1 = citation1.getStudent();
        student1.setName("李四");

        // 判断student和student1是否为同一个对象
        System.out.println("student和student1是否为同一个对象: " + (student == student1));

        // 调用show()方法
        citation.show();
        citation1.show();
    }
}

结果:

student和student1是否为同一个对象: true
李四同学:在2024学年第一学期中表现优秀,被评为三好学生。特发此状!
李四同学:在2024学年第一学期中表现优秀,被评为三好学生。特发此状!

student和student1对象是同一个对象,就会产生将student1对象的name属性改为“李四”,两个Citation(奖状)对象中显示的都是李四。这就是浅克隆的效果,对具体原型类(Citation)中的引用类型的属性进行引用的复制。针对此情况应使用深克隆,进行深克隆需要使用到对象流。代码如下:

public class CitationTest3 {
    public static void main(String[] args) throws Exception {
        // 创建原型对象
        Citation citation = new Citation();
        Student student = new Student("张三", 18);
        citation.setStudent(student);

        // 创建对象输出流对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\javaTest\\citation.txt"));
        // 将citation对象写入到文件中
        oos.writeObject(citation);
        oos.close();

        // 创建对象输入流对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\javaTest\\citation.txt"));
        // 从文件中读取奖状对象
        Citation citation1 = (Citation) ois.readObject();
        ois.close();
        // 获取citation1奖状所属学生对象
        Student student1 = citation1.getStudent();
        student1.setName("李四");

        // 判断student和student1是否为同一个对象
        System.out.println("student和student1是否为同一个对象: " + (student == student1));

        // 调用show()方法
        citation.show();
        citation1.show();
    }
}

结果:

student和student1是否为同一个对象: false
张三同学:在2024学年第一学期中表现优秀,被评为三好学生。特发此状!
李四同学:在2024学年第一学期中表现优秀,被评为三好学生。特发此状!

注意:
Citation和Student必须实现Serializable接口,否则会抛NotSerializableException异常。
image.png

github笔记

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

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

相关文章

飞书API(2):通过 Python 读取多维表数据

上一篇介绍了怎么通过官方的控制台调用飞书的 API 读取多维表数据,本篇介绍怎么通过 Python 读取多维表数据。 通过 Python 读取多维表主要分两步: 第一步是获取 access_token;第二步是拿 access_token 读取数据。 先说第二步,因…

SQLAlchemy 建立数据库模型之间的关系

常见关系: 一对多关系多对一关系多对多关系一对一关系 一对多关系(一个作者,多篇文章) ## 一对多关系,单作者-多文章,外键不可少 ## 外键(ForeignKey)总在多的那边定义,关系(relationship)总在单的那边定…

【计算机网络】四层负载均衡和七层负载均衡

前言 1、分层方式 首先我们知道,在计算机网络中,常用的协议分层方式:OSI和TCP/IP,以及实际生产中使用的协议划分方式。 在OSI中,各层的职责如下: 应用层:对软件提供接口以使程序能使用网络服…

CVAE——生成0-9数字图像(Pytorch+mnist)

1、简介 CVAE(Conditional Variational Autoencoder,条件变分自编码器)是一种变分自编码器(VAE)的变体,用于生成有条件的数据。在传统的变分自编码器中,生成的数据是完全由潜在变量决定的&…

9.图像中值腐蚀膨胀滤波的实现

1 简介 在第七章介绍了基于三种卷积前的图像填充方式,并生成了3X3的图像卷积模板,第八章运用这种卷积模板进行了均值滤波的FPGA实现与MATLAB实现,验证了卷积模板生成的正确性和均值滤波算法的MATLAB算法实现。   由于均值滤波、中值滤波、腐…

【QT+QGIS跨平台编译】054:【exiv2lib+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

点击查看专栏目录 文章目录 一、exiv2lib介绍二、文件下载三、文件分析四、pro文件五、编译实践一、exiv2lib介绍 exiv2lib 是一个用于处理图像元数据的开源 C++ 库。它可用于读取、编辑和写入图像文件中的 Exif 元数据(Exchangeable Image File Format,可交换图像文件格式)…

怎么打包出release.aar包

第一种 选择build variant 更改成release 第二钟 在gradle中选择相应任务来编译 选择assemble release如果没有这个选项,可能是你没有开启那个Task 收集的选项

机器学习——降维算法-奇异值分解(SVD)

机器学习——降维算法-奇异值分解(SVD) 在机器学习中,降维是一种常见的数据预处理技术,用于减少数据集中特征的数量,同时保留数据集的主要信息。奇异值分解(Singular Value Decomposition,简称…

为 Linux 中的 Docker 配置阿里云和网易云国内镜像加速下载中心

由于默认情况下,Docker 的镜像下载中心默认为国外的镜像中心,使用该镜像中心拉去镜像会十分缓慢,所以我们需要配置国内的 Docker 镜像下载中心,加速 Docker 镜像的拉取。Docker 的国内镜像下载中心常用的有:阿里云、网…

微信小程序(黑马优购:购物车页面)

1.渲染商品页面 <template><view><!-- 商品列表的标题区域 --><view class"cart-title"><!-- 左侧的图标 --><uni-icons type"shop" size"18"></uni-icons><!-- 右侧的文本 --><text class…

力扣 1143. 最长公共子序列

题目来源&#xff1a;https://leetcode.cn/problems/longest-common-subsequence/description/ C题解&#xff08;思路来源代码随想录&#xff09;&#xff1a;动态规划。 1. 确定dp数组&#xff08;dp table&#xff09;以及下标的含义 dp[i][j]&#xff1a;长度为[0, i - 1]…

Python之Opencv进阶教程(1):图片模糊

1、Opencv提供了多种模糊图片的方法 加载原始未经模糊处理的图片 import cv2 as cvimg cv.imread(../Resources/Photos/girl.jpg) cv.imshow(girl, img)1.1 平均值 关键代码 # Averaging 平均值 average cv.blur(img, (3, 3)) cv.imshow(Average Blur, average)实现效果 1.2…

备战蓝桥杯---贪心刷题1

话不多说&#xff0c;直接看题&#xff1a; 本质是一个数学题&#xff1a; 我们令xi<0表示反方向传递&#xff0c;易得我们就是求每一个xi的绝对值之和min,我们令平均值为a爸。 易得约束条件&#xff1a; x1-x2a1-a,x2-x3a2-a..... 解得x1x1-0,x2x1-((n-1)*a-a2-...an)。…

通过搜索引擎让大模型获取实时数据-实现类似 perplexity 的效果

文章目录 一、前言二、初衷三、实现方式四、总结 一、前言 汇报一下这周末的工作&#xff0c;主要是开发了一门课程&#xff1a;通过搜索引擎让大模型获取实时数据&#xff0c;第一次开发一门课程&#xff0c;难免会有很多不熟悉和做的不好的地方。 已经训练好的大模型有气数…

今天起,Windows可以一键召唤GPT-4了

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了人工智能中文站https://ai.weoknow.com 每天给大家更新可用的国内可用chatGPT资源 发布在https://it.weoknow.com 更多资源欢迎关注 微软 AI 大计的最后一块拼图完成了&#xff1f; 把 Copilot 按钮放在 Window…

【Linux】权限的基本概念

在本篇博客中&#xff0c;作者将会讲解在linux系统中&#xff0c;权限的基本概念。 一.什么是权限 通俗的讲&#xff0c;权限是用来约束人的。比如说&#xff1a;你买了某软件的vip会员&#xff0c;那么你就可以执行相对操作&#xff0c;如果你没买&#xff0c;则就会有权限约束…

Linux的中间件

我们先补充点关于awk的内容 awk的用法其实很广。 $0 表示整条记录 变量&#xff1a; NF 一行中有多少个字段&#xff08;表示字段数&#xff09; NR &#xff1a; 代表当前记录的序号&#xff0c;从1开始计数。每读取一条记录&#xff0c;NR的值就会自动增加1。&#xff08;…

基于ssm旅游资源网站(java项目+文档+源码)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的旅游资源网站。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 旅游资源网站的主要使用者分为管理…

稀碎从零算法笔记Day35-LeetCode:字典序的第K小数字

要考虑完结《稀碎从零》系列了哈哈哈 这道题和【LC.42 接雨水】&#xff0c;我愿称之为【笔试界的颜良&文丑】 题型&#xff1a;字典树、前缀获取、数组、树的先序遍历 链接&#xff1a;440. 字典序的第K小数字 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1…

Pytorch 下载失败原因

错误信息&#xff1a; ERROR: Could not find a version that satisfies the requirement torch (from versions: none) ERROR: No matching distribution found for torch 解决方案&#xff1a; 在官网看到&#xff0c;它需要python3.8-3.11的环境。过高和过低的版本都不…