Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >设计模式之原型模式

设计模式之原型模式

作者头像
爱撒谎的男孩
发布于 2018-05-25 08:11:05
发布于 2018-05-25 08:11:05
45400
代码可运行
举报
文章被收录于专栏:码猿技术专栏码猿技术专栏
运行总次数:0
代码可运行

创建型模式之原型模式

定义

  • 原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
  • 这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要 在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
  • 原型模式可以分为浅克隆和深度克隆

角色

角色

java语言中实现克隆的两种方式

  1. 直接创建一个对象,然后设置成员变量的值
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Obj obj=new Obj(); //创建一个新的对象
obj.setName(this.name);   //设置其中变量的值
obj.setAge(this.age);
  1. 实现cloneable接口

浅克隆

  • 如果克隆的对象的成员变量是值类型的,比如int,double那么使用浅克隆就可以实现克隆完整的原型对象,但是如果其中的成员变量有引用类型的,那么这个引用类型的克隆过去的其实是地址,克隆对象的这个引用类型变量改变了,那么原来变量的值也是会改变的。
  • 简单的说,浅克隆只能复制值类型的,对于引用类型的数据只能复制地址

浅克隆

实例

  • 一个公司出版周报,那么这个周报的格式一般是相同的,只是将其中的内容稍作修改即可。但是一开始没有这个原型,员工每周都需要重新手写这个周报,现在有了这个周报的原型,只需要在这个clone这个原型,然后在其基础上修改即可。

周报

  • 其中的Cloneable就是抽象原型类
  • 附件类(这个是一个引用类型的对象,验证浅克隆只是复制其中的地址,如果两个对象中的任何一个改变了这个变量的值,那么另外一个也会随之改变)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
 * 附件类,这个是周报的附件
 */
public class Attachment {
	private String name; // 名称

	public Attachment(String name) {
		super();
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}
  • 周报的类(其中实现了Cloneable接口)
    • 其中的clone()方法返回的就是一个克隆的对象,因此我们调用这个方法克隆一个新的对象
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
 * 这个是周报类,这个类是实现接口Prototype这个接口的
 */
public class WeeklyLog implements Cloneable {
	private String name; // 姓名
	private String date; // 日期
	private String content; // 内容
	private Attachment attachment;  //附件,是一个引用对象,这个只能实现浅克隆
	public WeeklyLog() {
		super();
	}
	/**
	 * 构造方法
	 */
	public WeeklyLog(String name, String date, String content) {
		super();
		this.name = name;
		this.date = date;
		this.content = content;
	}
	/**
	 * 提供一个clone方法,返回的是一个clone对象
	 */
	public WeeklyLog clone() {
		Object object = null; // 创建一个Object对象
		try {
			object = super.clone(); // 直接调用clone方法,复制对象
			return (WeeklyLog) object; // 返回即可
		} catch (CloneNotSupportedException e) {
			System.out.println("这个对象不能复制.....");
			return null;
		}
	}

}
  • 测试类
    • 测试浅克隆的值类型是是否完成复制了
    • 测试引用类型的值能否完成克隆,还是只是复制了一个引用地址
    • 从结果来看,对象是完成复制了,因为判断两个对象的地址是不一样的,但是其中的引用类型的成员变量没有完成复制,只是复制了一个地址
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Client {
	public static void main(String[] args) throws CloneNotSupportedException {

		WeeklyLog p1 = new WeeklyLog("陈加兵", "第一周", "获得劳动模范的称号..."); // 创建一个对象
		Attachment attachment = new Attachment("消息");
		p1.setAttachment(attachment); // 添加附件
		WeeklyLog p2 = p1.clone();
		System.out.println(p1 == p2); // 判断是否正确
		p2.setName("Jack"); // 修改P2对象的内容
		p2.setDate("第二周");
		p2.setContent("工作认真.....");
		System.out.println(p2.getName());
		// 返回true,可以知道这两个附件的地址是一样的
		System.out.println(p1.getAttachment() == p2.getAttachment());
	}
}

总结

  • 浅克隆对于值类型的数据可以复制成功,但是对于引用卡类型的数据只能复制一个地址,如果一个对象中的引用类型的变量的值改变了,那么另外一个也会随之改变

深度克隆

  • 浅克隆只能完成复制值类型,深度克隆可以完成复制引用类型和值类型

深度克隆

条件

  1. 引用类型的变量类实现序列化(实现Serializabl接口)
  2. 需要克隆的类实现序列化(实现Serializable接口)

为什么实现序列化

  • 因为深度克隆的实现的原理是使用输入和输出流,如果想要将一个对象使用输入和输出流克隆,必须序列化。

实现

  • 附件类(引用类型的成员变量,实现序列化)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
 * 附件类,这个是周报的附件
 */
public class Attachment implements Serializable{
	private static final long serialVersionUID = -799959163401886355L;
	private String name; // 名称
	public Attachment(String name) {
		super();
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}
  • 周报类(需要克隆的类,因为其中有引用类型的成员变量,因此需要实现序列化)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
 * 这个是周报类,这个类是实现接口Prototype这个接口的
 */
public class WeeklyLog implements Serializable {
	private static final long serialVersionUID = -8782492113927035907L;
	private String name; // 姓名
	private String date; // 日期
	private String content; // 内容
	private Attachment attachment; // 附件,是一个引用对象,这个只能实现浅克隆
	public WeeklyLog() {
		super();
	}
	/**
	 * 构造方法
	 */
	public WeeklyLog(String name, String date, String content) {
		super();
		this.name = name;
		this.date = date;
		this.content = content;
	}
	/**
	 * 提供一个clone方法,返回的是一个clone对象
	 */
	public WeeklyLog clone() {
		// 将对象写入到对象流中
		ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
		try {
			ObjectOutputStream objectOutputStream = new ObjectOutputStream(
					arrayOutputStream); // 创建对象输出流
			objectOutputStream.writeObject(this); // 将这个类的对象写入到输出流中
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}

		// 将对象从流中读出
		ByteArrayInputStream arrayInputStream = new ByteArrayInputStream(
				arrayOutputStream.toByteArray());
		WeeklyLog weeklyLog;
		try {
			ObjectInputStream objectInputStream = new ObjectInputStream(
					arrayInputStream);// 新建对象输入流
			weeklyLog = (WeeklyLog) objectInputStream.readObject(); // 读取对象从流中
			return weeklyLog;
		} catch (IOException | ClassNotFoundException e) {
			e.printStackTrace();
			return null;
		}

	}

}
  • 测试类
    • 从中可以看出其中的附件地址是不同的,如果一个对象的附件变量改变了,那么另外一个将保持不变,因此实现了深度克隆,是两个完全不同的对象
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Client {
	public static void main(String[] args) throws CloneNotSupportedException {

		WeeklyLog p1 = new WeeklyLog("陈加兵", "第一周", "获得劳动模范的称号..."); // 创建一个对象
		Attachment attachment = new Attachment("消息");
		p1.setAttachment(attachment); // 添加附件
		WeeklyLog p2 = p1.clone();
		System.out.println(p1 == p2); // 判断是否正确
		p2.setName("Jack"); // 修改P2对象的内容
		p2.setDate("第二周");
		p2.setContent("工作认真.....");
		System.out.println(p2.getName());
		//返回false,可以看出这个是不同的地址,因此完成了深克隆
		System.out.println(p1.getAttachment() == p2.getAttachment());
	}
}

总结

  • 因为深度克隆使用的是将对象写入输入和输出流中的,因此需要实现序列化,否则将不能完成

总结

  1. 浅克隆只能克隆对象中的值类型,不能克隆有引用类型成员变量的对象
  2. 使用深度克隆:
    • 引用类型的成员变量的类必须实现序列化
    • 需要克隆的类必须实现序列化
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-04-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
设计模式 ☞ 创新型模式之原型模式
  原型(Prototype)模式的定义如下:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。例如,Windows 操作系统的安装通常较耗时,如果复制就快了很多。
Demo_Null
2020/12/29
4290
原型模式
浅克隆(Shallow Clone):当原型对象被复制时,只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制。
千羽
2021/12/29
4480
原型模式
设计模式之原型模式(创建型)
原型模式(Prototype Pattern):原型模式是提供一个原型接口,提供原型的克隆,创建新的对象,是一种对象创建型模式。
SmileNicky
2019/03/06
3870
Java进阶篇设计模式之三 ----- 建造者模式和原型模式
在上一篇中我们学习了工厂模式,介绍了简单工厂模式、工厂方法和抽象工厂模式。本篇则介绍设计模式中属于创建型模式的建造者模式和原型模式。
格姗知识圈
2019/07/19
3610
Design Patterns 之原型模式
原型(Prototype)模式的定义如下:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。例如,Windows 操作系统的安装通常较耗时,如果复制就快了很多。在生活中复制的例子非常多,这里不一一列举了。
wsuo
2020/12/02
3350
Design Patterns 之原型模式
一起学习设计模式--05.原型模式
《西游记》中的孙悟空吹猴毛变出很多猴兵的故事想必大家都知道,《火影》中鸣人的多重影分身大部分人应该也是都知道,他们都可以根据自己的形象,复制(又称克隆)出很多和自己一摸一样的“身外身”来。在设计模式中也存在一个类似的模式,可以通过一个原型对象克隆出多个一模一样的对象,该模式被成为原型模式。
独立观察员
2022/12/06
3710
一起学习设计模式--05.原型模式
设计模式的征途—5.原型(Prototype)模式
相信大多数的人都看过《西游记》,对孙悟空拔毛变出小猴子的故事情节应该都很熟悉。孙悟空可以用猴毛根据自己的形象复制出很多跟自己一模一样的小猴兵出来,其实在设计模式中也有一个类似的模式,我们可以通过一个原型对象来克隆出多个一模一样的对象,这个模式就是原型模式。
Edison Zhou
2018/08/21
5800
设计模式的征途—5.原型(Prototype)模式
浅析克隆 顶
一、在浅克隆中,如果原型对象的属性是值类型(如int,double,byte,boolean,char等),将复制一份给克隆对象;如果原型对象的属性是引用类型(如类,接口,数组,集合等复杂数据类型),则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的属性指向相同的内存地址。简单来说,在浅克隆中,当原型对象被复制时只复制它本身和其中包含的值类型的属性,而引用类型的属性并没有复制。
算法之名
2019/08/20
5580
设计模式——原型模式
设计模式——原型模式
Java架构师必看
2021/05/14
3520
设计模式——原型模式
设计模式-原型模式示例
在这个示例代码中,我们定义了一个原型接口 Prototype 和一个具体的学生类 Student,该类实现了原型接口并重写了 clone() 方法。在客户端代码中,我们创建了一个原型对象 stu1,并通过克隆原型对象来生成一个新的学生对象 stu2,然后修改 stu2 对象的属性并打印结果。由于 stu1 和 stu2 对象是互相独立的,因此修改 stu2 的属性不会影响 stu1 对象的属性。
堕落飞鸟
2023/05/03
2390
设计模式学习笔记之原型模式
这是一篇学习笔记,内容很多是来源于网上的资料,按照自己学习情况进行的总结。 我的个人博客:海加尔金鹰
海加尔金鹰
2020/06/09
3070
设计模式-原型模式(克隆羊多利看了都说好)
问题: 现在有一只羊(包含属性:名字Dolly、年龄2),需要克隆10只属性完全相同的羊。
唔仄lo咚锵
2021/09/14
4160
设计模式-原型模式(克隆羊多利看了都说好)
原型模式(Prototype)
原型模式的结构 原型模式包含以下3个角色: •Prototype(抽象原型类) •ConcretePrototype(具体原型类) •Client(客户类)
happlyfox
2018/10/31
4270
设计模式---原型模式
原型模式(Prototype Pattern):使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式是一种对象创建型模式。
大忽悠爱学习
2021/11/15
4530
Java设计模式之原型模式
现在有一只羊,姓名为:tom,年龄为:1,颜色为:白色,请编写程序创建和tom羊属性完全相同的10只羊。
shaoshaossm
2022/12/27
2640
设计模式之原型模式
我们在创建对象时,通常是通过new关键字来创建的。但是,思考一下,如果当前类的构造函数很复杂,每次new对象时都会消耗非常多的资源,这样肯定是不行的,耗时又费力。
烟雨星空
2020/06/16
3300
Java原型模式(prototype)
  prototype模式也就是原型模式,是javaGOF23种设计模式中的一种,我们在学习spring的时候在bean标签的学习中碰到过,所以本文来给大家介绍下原型模式
用户4919348
2019/04/02
1.6K0
Java原型模式(prototype)
原型模式的用法
用一个已经创建的实例作为原型,通过**复制**该原型对象来创建一个和原型对象**相同的新对象**。
忆愿
2024/08/04
1280
原型模式的用法
Java设计模式(五)----原型模式
原型模式(Prototype) 一、概述 二、结构 三、浅度克隆和深度克隆  浅度克隆  深度克隆 一、概述  定义:原型模式属于对象的创建模式。通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象。简言之:就是复制粘贴。这就是选型模式的用意。 二、结构 原型模式主要用于对象的复制,它的核心是就是类图中的原型类Prototype。Prototype类需要具备以下两个条件: 1、实现Cloneable接口。在java语言有一个
汤高
2018/01/11
7660
Java设计模式(五)----原型模式
【设计模式自习室】原型模式
原型模式要求对象实现一个可以克隆自身的接口(类型)。这样一来,通过原型实例创建新的对象。
蛮三刀酱
2019/12/30
4660
【设计模式自习室】原型模式
相关推荐
设计模式 ☞ 创新型模式之原型模式
更多 >
领券
一站式MCP教程库,解锁AI应用新玩法
涵盖代码开发、场景应用、自动测试全流程,助你从零构建专属AI助手
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档