【设计模式】创建型模式·原型模式

news2024/11/28 10:54:19

设计模式学习之旅(五)
查看更多可关注后查看主页设计模式DayToDay专栏

一. 概述

用一个已经创建的实例作为原型,通过复制(克隆)该原型对象来创建一个和原型对象相同的新对象。

原型模式包含如下角色:

  • 抽象原型类:规定了具体原型对象必须实现的的 clone() 方法。
  • 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
  • 访问类:使用具体原型类中的 clone() 方法来复制新的对象。

接口类图如下:

在这里插入图片描述


二.实现

原型模式的克隆分为浅克隆和深克隆。

浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本(引用)类型属性,仍指向原有属性所指向的对象的内存地址。

深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

(1) 浅克隆

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();
    }
}

PrototypeTest(测试访问类):

public class PrototypeTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Realizetype r1 = new Realizetype();
        Realizetype r2 = r1.clone();

        System.out.println("对象r1和r2是同一个对象?" + (r1 == r2));
    }
}

(1.1) 案例

用原型模式生成“三好学生”奖状

同一学校的“三好学生”奖状除了获奖人姓名不同,其他都相同,可以使用原型模式复制多个“三好学生”奖状出来,然后在修改奖状上的名字即可。

类图如下:
在这里插入图片描述

代码如下:

//奖状类
public class Citation implements Cloneable {
    private String name;

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

    public String getName() {
        return (this.name);
    }

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

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

//测试访问类
public class CitationTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Citation c1 = new Citation();
        c1.setName("张三");

        //复制奖状
        Citation c2 = c1.clone();
        //将奖状的名字修改李四
        c2.setName("李四");

        c1.show();
        c2.show();
    }
}

(1.2) 使用场景

  • 对象的创建非常复杂,可以使用原型模式快捷的创建对象。
  • 性能和安全要求比较高。

(2) 深克隆

将上面的“三好学生”奖状的案例中Citation类的name属性修改为Student类型的属性。代码如下:

//奖状类
public class Citation implements Cloneable,Serializable {
    private Student stu;

    public Student getStu() {
        return stu;
    }

    public void setStu(Student stu) {
        this.stu = stu;
    }

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

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

//学生类
public class Student implements Serializable {
    private String name;
    private String address;

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

    public Student() {
    }

    public String getName() {
        return name;
    }

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

    public String getAddress() {
        return address;
    }

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

//测试类
public class CitationTest {
    public static void main(String[] args) throws CloneNotSupportedException {

        Citation c1 = new Citation();
        Student stu = new Student("张三", "西安");
        c1.setStu(stu);

        //复制奖状
        Citation c2 = c1.clone();
        //获取c2奖状所属学生对象
        Student stu1 = c2.getStu();
        stu1.setName("李四");

        //判断stu对象和stu1对象是否是同一个对象
        System.out.println("stu和stu1是同一个对象?" + (stu == stu1));

        c1.show();
        c2.show();
    }
}

运行结果为:
在这里插入图片描述

  • 说明:stu对象和stu1对象是同一个对象,就会产生将stu1对象中name属性值改为“李四”,两个Citation(奖状)对象中显示的都是李四。这就是浅克隆的效果,对具体原型类(Citation)中的引用类型的属性进行引用的复制。这种情况需要使用深克隆,而进行深克隆需要使用对象流。
  • 代码如下:
public class CitationTest1 {
    public static void main(String[] args) throws Exception {
        Citation c1 = new Citation();
        Student stu = new Student("张三", "西安");
        c1.setStu(stu);

        //创建对象输出流对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\Think\\Desktop\\b.txt"));
        //将c1对象写出到文件中
        oos.writeObject(c1);
        oos.close();

        //创建对象出入流对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\Think\\Desktop\\b.txt"));
        //读取对象
        Citation c2 = (Citation) ois.readObject();
        //获取c2奖状所属学生对象
        Student stu1 = c2.getStu();
        stu1.setName("李四");

        //判断stu对象和stu1对象是否是同一个对象
        System.out.println("stu和stu1是同一个对象?" + (stu == stu1));

        c1.show();
        c2.show();
    }
}

运行结果为:
在这里插入图片描述

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

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

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

相关文章

Java基础(二)

1.标识符标识符:由数字、字符、下划线、$组成(不能以数字、下划线开头)java严格区分大小写2.命名规范包名:多单词组成时所有字母全部小写类名、接口名:多单词组成时,所有单词首字母大写变量名、方法名&…

屏幕录制工具哪个好用?分享3款相见恨晚的软件

在我们的日常生活中,我们经常使用截图和手机屏幕记录功能来记录一些重要的内容。然而,录制的图片清晰度很低,或者需要不断的截图,这很容易出错一些重要的内容,这个时候就需要进行录屏了。那么电脑上的屏幕录制工具哪个…

group by详解

group by功能 在SQL中group by主要用来进行分组统计,分组字段放在group by的后面;分组结果一般需要借助聚合函数实现。 group by语法结构 1、常用语法 语法结构 SELECT column_name1,column_name2, … 聚合函数1,聚合函数2 , … FROM table_name GROUP…

电脑删除了大文件怎么恢复?看看这四种方法

电脑能够帮助我们存储大量的文件,比如视频、文档、音频等,但是随着时间的流逝,有些文件所存在的意义也变得毫无价值了,这时候很多小伙伴都会选择删除操作,可是由于电脑磁盘内容过多,容易面临重要文件被误删…

硬件仿真加速器与原型验证平台

基于软件仿真工具对于动辄几百万门的ASIC验证而言,几乎显得力不从心。不管是从成本还是从性能的角度来看,使用硬件仿真器或者基于FPGA的原型验证平台,几乎是验证工程师的不二法门。因为基于硬件的环境能够极大的提高验证的速度,增…

Promise(基础)

Promise是什么 1.promise是一门新的技术(ES6规范) 2.Promise是JS中一编程的解决方案(旧的解决方案是单纯的使用回调函数) 3.promise一个构造函数,promise队形用来封装一个一步操作并可以获取其成功/失败的结果值。 注…

sparksql案例实操

sparksql案例实操解决语句如下 select * from( select , rank()over(partition by area order by clickCnt desc) from(select area, product_name, count()as clickCnt from( select a.*, p.product_name, c.area, c.city_name from user_visit_action a join product_info p…

Dubbo与Spring集成

Dubbo框架常被当作第三方框架集成到应用中,当Spring集成Dubbo框架后,为什么在编写代码的时候,只用了DubboReference注解就可以调用提供方的服务了呢?这篇笔记就是分析Dubbo框架是怎么与Spring结合的。 现状integration层代码编写…

关于嵌入式学习和规划,求指点?

在知乎上收到的一个提问问题:各位大佬好,我先说说基本情况,28岁,北京,嵌入式软开,军工行业。硕士毕业一年半。工作不忙收获很少,造成我自己特别迷茫,没有了方向,自己学没…

【C++】Hash闭散列

目录 一、哈希的概念 1.1 哈希冲突 1.2 哈希函数 1.3 装载因子 二、闭散列 2.1 线性探测 2.2 Insert 插入 2.3 Find 查找 2.4 Erase删除 2.5 插入复杂类型 2.6 二次探测 三、源代码与测试用例 3.1 hash源代码 3.2 测试用例 一、哈希的概念 在前面学习了二叉搜索…

多巴胺聚乙二醇多巴胺,Dopamine-PEG-Dopamine简介,多巴胺是具有正性肌力活动的单胺化合物

产品名称:多巴胺聚乙二醇多巴胺,双多巴胺聚乙二醇(Dopamine-PEG-Dopamine) 中文别名:多巴胺PEG多巴胺,双多巴胺聚乙二醇 英文名称:Dopamine-PEG-Dopamine 存储条件:-20C&#xff0…

磨金石教育影视技能干货分享|浅析中国CG特效的发展现状

中国CG特效的发展2015年是一个分水岭。在2015年之前,中国CG 特效发展是混乱的,不成熟的。总体表现就是技术水平不足,缺少人才培养的体系。当时从事CG的公司,大概有两个类型:“技术型与业务型”。所谓技术型的公司&…

设计模式_结构型模式 -《装饰器模式》

设计模式_结构型模式 -《装饰器模式》 笔记整理自 黑马程序员Java设计模式详解, 23种Java设计模式(图解框架源码分析实战) 概述 我们先来看一个快餐店的例子。 快餐店有炒面、炒饭这些快餐,可以额外附加鸡蛋、火腿、培根这些配菜…

PowerDesigner设计表时显示注释列Comment

首先,使用 PowerDesigner 新建模型,File —> New Model 然后,切换到模型类型(Model types)选项卡,选中 Physical Diagram 然后点击右侧表格图标,在左侧面板中创建表格如下。双击表格,找到Columns选项卡…

招标采购中,如何编写有效的RFI(信息邀请书)?

在企业招标采购过程中,RFI(信息邀请书)是一个从商品或服务的潜在供应商处收集信息的正式流程。RFI旨在由客户编写并发送给潜在供应商。RFI通常是第一个也是最广泛的一系列请求,旨在缩小潜在供应商候选人名单。 当企业对潜在供应…

【实际开发07】- XxxxController 批量处理 × 5 -【model】

目录 1. Mode 1. IotTypeController 基础 7 tips 2. 辅助添加 Validated 无法覆盖的 参数校验 1. 预处理空指针异常 ( 校验 : 核心必填参数 not null ) 3. RequestBody 对应API 存在 feign 调用时 , 注意 : 不可缺省 1. feign API 需要加 RequestBody , Controller 层可…

手工测试 | 黑盒测试方法论—边界值

本文节选自霍格沃兹测试学院内部教材 边界值分析法是一种很实用的黑盒测试用例方法,它具有很强的发现故障的能力。边界值分析法也是作为对等价类划分法的补充,测试用例来自等价类的边界。 这个方法其实是在测试实践当中发现,Bug 往往出现在定…

OpenCV4.6 VS 4.7 QRCode解码功能效果对比

导 读 本文主要对OpenCV4.7.0和4.6.0中QRCode检测/解码功能做简单的测试对比,供大家参考。 背景介绍 最近OpenCV更新到了4.7.0版本,在ChangeLog算法部分除了新增Stackblur滤波算法(详细介绍见下面链接),还有对QRCode检测和解码的改进。 吊打…

实现通讯录(C语言)

功能实现 实现步骤: 创建通讯录 初始化通讯录 打印菜单 实现选择功能 实现添加功能 实现删除功能 实现查找功能 实现修改功能 实现清空功能 实现排序功能 实现查询所有联系人信息功能 通讯录总代码 创建通讯录 1、创建成员信息结构体 我们用结构体来封装一个联系人…

【系列04】数组 多维数组 冒泡排序 稀疏数组[有目录]

数组声明和创建 变量类型 变量名称 变量的值 声明数组 int []nums;//定义//上面是首选 /*也可以 int nums2[];*/下面这种写法是为了迎合c与c用户的喜爱,更推荐用上面的定义 方式 创建数组 numsnew int[10];定义数组计算数组的和 package com.SunAo.array; //变量类型 变量名称…