概述

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

结构

原型模式包含如下角色:

  • 抽象原型类:规定了具体原型对象必须实现的的 clone() 方法。

  • 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。

  • 访问类:使用具体原型类中的 clone() 方法来复制新的对象。

接口类图如下:

实现

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

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

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

案例

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

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

类图如下:

代码如下:

//奖状类
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();
}
}

使用场景

  • 对象的创建非常复杂,可以使用原型模式快捷的创建对象。

  • 性能和安全要求比较高。

扩展(深克隆)

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

//奖状类
public class Citation implements Cloneable {
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 {
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异常。

往期推荐

【设计模式】从零开始,用原型模式简化你的Java对象创建过程!的更多相关文章

  1. C#设计模式之五原型模式(Prototype Pattern)【创建型】

    一.引言 在开始今天的文章之前先说明一点,欢迎大家来指正.很多人说原型设计模式会节省机器内存,他们说是拷贝出来的对象,这些对象其实都是原型的复制,不会使用内存.我认为这是不对的,因为拷贝出来的每一个对 ...

  2. 深度分析:java设计模式中的原型模式,看完就没有说不懂的

    前言 原型模式(Prototype模式)是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象 原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的 ...

  3. 设计模式学习心得<原型模式 Prototype >

    原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式是实现了一个原型接口,该接口用于创建当 ...

  4. 重学 Java 设计模式:实战原型模式

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 老板你加钱我的代码能飞 程序员这份工作里有两种人:一类是热爱喜欢的.一类是仅当成工作 ...

  5. java23种设计模式——四、原型模式

    源码在我的github和gitee中获取 目录 java23种设计模式-- 一.设计模式介绍 java23种设计模式-- 二.单例模式 java23种设计模式--三.工厂模式 java23种设计模式- ...

  6. 设计模式のPrototypePattern(原型模式)----创建模式

    一.产生的背景 这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆.当直接创建对象的代价比较大时,则采用这种模式.例如,一个对象需要在一个高代价的数据库操作之后被创建.我们可以缓存该对象,在下 ...

  7. 设计模式之GOF23原型模式01

    原型模式prototype 原型模式: - 通过new产生一个对象需要非常繁琐的数据准备或者访问权限,则可以使用原型模式,比如如果new对象所需时间过长,可以通过克隆产生相同的副本 - Java中的克 ...

  8. Java设计模式5:原型模式

    原型模式 原型模式属于对象的创建模式,通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象,这就是原型模式的用意. 原型模式结构 原型模式要求对象实现一个 ...

  9. 设计模式系列之原型模式(Prototype Pattern)——对象的克隆

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  10. Net设计模式实例之原型模式( Prototype Pattern)

    一.原型模式简介(Brief Introduction) 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象. Specify the kin ...

随机推荐

  1. MSSQL 发布订阅,实现读写分离 SQL Server

    https://blog.csdn.net/qq_32343577/article/details/82423393 -查询服务器的名称和实际计算机的名称,如果两者不一致,就需要修改. use mas ...

  2. 《好好学Java 从零基础到项目实战》姗姗而来

    梦里寻她千百度,千呼万唤始出来.从决定开始写这本书,到最终出版上市,数数已经是第三个夏天了.今年疫情有点紧,各行各业都受到影响,多亏出版社各位老师东奔西走,总算排除了万般艰难险阻,这才有了<好好 ...

  3. Windows链接创建神器:一键生成符号链接与硬链接的智能批处理工具【NuGet】

    [自用工具]NuGet 或各项目中共用部分目录或文件,利用DOS符号链接解决重复文件的多份拷贝,起到节省磁盘空间的作用. 告别复杂的命令行操作!这款增强版批处理脚本让Windows链接创建变得简单.直 ...

  4. centos8 yum替换阿里源

    解决centos7使用yum安装mysql 下载速度慢的问题 挺好用的,之前用腾讯云安装了半天,太慢了,改过之后速度快多了. 1.首先备份系统自带yum源配置文件/etc/yum.repos.d/Ce ...

  5. 从零开始实现简易版Netty(三) MyNetty 高效的数据读取实现

    从零开始实现简易版Netty(三) MyNetty 高效的数据读取实现 1. MyNetty 数据读取处理优化 在上一篇博客中,lab2版本的MyNetty实现了基本的reactor模型和一个简易的p ...

  6. 解决Ubuntu上使用fsck命令时遇到的“The superlock could not be read......”的问题

    问题产生原因:我也不太清楚,可能是给硬盘分区的时候出的问题. 问题解决方法:依次执行以下的命令,请根据实际情况调整存储设备名称. 注意:下面的操作会清空硬盘所有数据,请根据自己的需求来判断是否需要执行 ...

  7. 前端开发系列014-基础篇之Javascript面向对象(三)

    一.原型对象相关方法 ❏ in 关键字 ❏ instanceof ❏ hasOwnProperty方法 ❏ constructor构造器属性 ❏ isProtoTypeOf方法 in关键字 作用 用来 ...

  8. paraview 导出表面网格

    简介 RT 步骤 如下所示 然后save data即可

  9. 存储数据库的传输效率提升-ETLCloud结合HBASE

    一.大数据存储数据库--HBASE HBase,作为一个开源的分布式列存储数据库,基于Google的Bigtable设计而成,专为处理大规模结构化数据而优化.使用HBase打造大数据解决方案的好处主要 ...

  10. Product-Mechanics: 玻璃:开模+ 浇筑 量产: 高硼硅玻璃/容器/器皿

    Product-Mechanics: 塑料:开模+挤塑量产 高硼硅玻璃: 专利: https://www.xjishu.com/zhuanli/25/201910127975.html 例如化学仪器设 ...