java常用设计模式三:原型模式
在说原型模式之前先说一下浅拷贝和深拷贝的概念
一、浅拷贝和深拷贝
1、浅拷贝
在java中,对象创建后需要有一个引用变量来指向该对象实际的地址空间,也就是说引用变量与对象实体是两个不同的数据体。在Object类的clone()方法中。
对对象字段进行复制时,如果字段是String 和8种基本数据类型(int,boolean,char,byte,short,float,double.long)包括对应的封装类,则会复制字段的值到一个新的变量中;而字段是引用类型,则仅会将引用值复制给新对象中的相应字段中,也就是说,两个字段指向了同一个对象实例。看以下的例子来理解浅拷贝。
1)用户类
public class User{
private String name;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
2)学生类:如果要让Student类支持clone方法,必须实现Cloneable接口
public class Student implements Cloneable {
private User user;
private String message;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
/**
* 重写clone()方法为public类型,实现拷贝功能
*/
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
3)测试类
public class TestCopy {
public static void main(String[] args) throws CloneNotSupportedException {
User user = new User();
user.setName("张三");
user.setSex("男");
Student oldStudent = new Student();
oldStudent.setUser(user);
oldStudent.setMessage("old message");
System.out.println("oldStudent:"+oldStudent.getUser().getName()+" :"+oldStudent.getUser().getSex()+" :"+oldStudent.getMessage());
Student copyStudent = (Student) oldStudent.clone();
System.out.println("copyStudent:"+copyStudent.getUser().getName()+" :"+copyStudent.getUser().getSex()+" :"+copyStudent.getMessage());
System.out.println("oldStudent == copyStudent ? " +(oldStudent == copyStudent));
copyStudent.getUser().setName("李丽");
copyStudent.getUser().setSex("女");
copyStudent.setMessage("new message");
System.out.println("修改copyStudent的内容后===========");
System.out.println("oldStudent:"+oldStudent.getUser().getName()+" :"+oldStudent.getUser().getSex()+" :"+oldStudent.getMessage());
System.out.println("copyStudent:"+copyStudent.getUser().getName()+" :"+copyStudent.getUser().getSex()+" :"+copyStudent.getMessage());
}
}
oldStudent:张三 :男 :old message
copyStudent:张三 :男 :old message
oldStudent == copyStudent ? false
修改copyStudent的内容后===========
oldStudent:李丽 :女 :old message
copyStudent:李丽 :女 :new message
由以上结果可知道,oldStudent和copyStudent并不是同一个对象,当将copyStudent的user信息和message信息修改后,oldStudent的user信息相应也改变了,oldStudent的message没有改变。
得出结论:在进行用Object类对Student的User属性进行拷贝时是浅拷贝,也就是说只是将oldStudent里面user引用变量复制到了copyStudent里面,2个变量实际上指向的是同一块地址。

2、深拷贝
那就是对于引用型变量,深拷贝会开辟一块新的内存空间,将被复制引用所指向的对象实例的各个属性复制到新的内存空间中,然后将新的引用指向块内存(也就是一个新的实例)。以后对新引用指向的实例属性进行修改的时候就不会影响到老引用指向的实例属性。

我们将浅拷贝的例子修改下:
1)用户类:也实现了Cloneable接口
public class User implements Cloneable{
private String name;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
/**
* 由于User类里面只有基本数据类型的封装类,所以调用Object.clone()方法得到的是深拷贝内容
* @return
* @throws CloneNotSupportedException
*/
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
2)学生类也修改如下:主要是clone方法
public class Student implements Cloneable {
private User user;
private String message;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
/**
* 重写clone()方法为public类型,然后实现深拷贝功能。
*/
@Override
public Object clone() throws CloneNotSupportedException {
Student student = (Student)super.clone();
student.user = (User) user.clone();
return student;
}
}
3)测试类不变
public class TestCopy {
public static void main(String[] args) throws CloneNotSupportedException {
User user = new User();
user.setName("张三");
user.setSex("男");
Student oldStudent = new Student();
oldStudent.setUser(user);
oldStudent.setMessage("old message");
System.out.println("oldStudent:"+oldStudent.getUser().getName()+" :"+oldStudent.getUser().getSex()+" :"+oldStudent.getMessage());
Student copyStudent = (Student) oldStudent.clone();
System.out.println("copyStudent:"+copyStudent.getUser().getName()+" :"+copyStudent.getUser().getSex()+" :"+copyStudent.getMessage());
System.out.println("oldStudent == copyStudent ? " +(oldStudent == copyStudent));
copyStudent.getUser().setName("李丽");
copyStudent.getUser().setSex("女");
copyStudent.setMessage("new message");
System.out.println("修改copyStudent的内容后===========");
System.out.println("oldStudent:"+oldStudent.getUser().getName()+" :"+oldStudent.getUser().getSex()+" :"+oldStudent.getMessage());
System.out.println("copyStudent:"+copyStudent.getUser().getName()+" :"+copyStudent.getUser().getSex()+" :"+copyStudent.getMessage());
}
}
oldStudent:张三 :男 :old message
copyStudent:张三 :男 :old message
oldStudent == copyStudent ? false
修改copyStudent的内容后===========
oldStudent:张三 :男 :old message
copyStudent:李丽 :女 :new message
由以上执行结果可知:对copyStudent的修改并不会影响到oldStudent,因此实现了深拷贝。
还可以通过序列化和反序列化实现 深拷贝
User类:要实现序列化
public class User implements Serializable{
private String name;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
Student类:要实现序列化
public class Student implements Serializable {
private User user;
private String message;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
/**
* 注意,这个clone()方法已不再是Object类的clone方法了
*/
public Student clone(){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteArrayInputStream bais = null;
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
Student student = null;
try {
oos = new ObjectOutputStream(baos);
//将本身实例写入流中
oos.writeObject(this);
bais=new ByteArrayInputStream(baos.toByteArray());
ois = new ObjectInputStream(bais);
student = (Student)ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return student;
}
测试类:
public class TestCopy {
public static void main(String[] args) {
User user = new User();
user.setName("张三");
user.setSex("男");
Student oldStudent = new Student();
oldStudent.setUser(user);
oldStudent.setMessage("old message");
System.out.println("oldStudent:"+oldStudent.getUser().getName()+" :"+oldStudent.getUser().getSex()+" :"+oldStudent.getMessage());
Student copyStudent = oldStudent.clone();
System.out.println("copyStudent:"+copyStudent.getUser().getName()+" :"+copyStudent.getUser().getSex()+" :"+copyStudent.getMessage());
System.out.println("oldStudent == copyStudent ? " +(oldStudent == copyStudent));
copyStudent.getUser().setName("李丽");
copyStudent.getUser().setSex("女");
copyStudent.setMessage("new message");
System.out.println("修改copyStudent的内容后===========");
System.out.println("oldStudent:"+oldStudent.getUser().getName()+" :"+oldStudent.getUser().getSex()+" :"+oldStudent.getMessage());
System.out.println("copyStudent:"+copyStudent.getUser().getName()+" :"+copyStudent.getUser().getSex()+" :"+copyStudent.getMessage());
}
}
oldStudent:张三 :男 :old message
copyStudent:张三 :男 :old message
oldStudent == copyStudent ? false
修改copyStudent的内容后===========
oldStudent:张三 :男 :old message
copyStudent:李丽 :女 :new message
3、原型模式
定义:使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式是一种对象创建型模式。
设计思路:原型模式要求对象实现一个可以“克隆”自身的接口,这样就可以通过复制一个实例对象本身来创建一个新的实例。这样一来,通过原型实例创建新的对象,就不再需要关心这个实例本身的类型,只要实现了克隆自身的方法,就可以通过这个方法来获取新的对象,而无须再去通过new来创建。
上面浅拷贝和深拷贝的2个例子,其实就是原型模式的表现形式之一。
java常用设计模式三:原型模式的更多相关文章
- Java设计模式05:常用设计模式之原型模式(创建型模式)
1. Java之原型模式(Prototype Pattern) 原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象. ...
- java常用设计模式总览
一.java的设计模式大体上分为三大类: 创建型模式(5种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式. 结构型模式(7种):适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组 ...
- JAVA 设计模式之原型模式
目录 JAVA 设计模式之原型模式 简介 Java实现 1.浅拷贝 2.深拷贝 优缺点说明 1.优点 2.缺点 JAVA 设计模式之原型模式 简介 原型模式是六种创建型设计模式之一,主要应用于创建相同 ...
- java设计模式4——原型模式
java设计模式4--原型模式 1.写在前面 本节内容与C++语言的复制构造函数.浅拷贝.深拷贝极为相似,因此建议学习者可以先了解C++的该部分的相关知识,或者学习完本节内容后,也去了解C++的相应内 ...
- 设计模式之 原型模式详解(clone方法源码的简单剖析)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 原型模式算是JAVA中最简单 ...
- 设计模式_11_原型模式(prototype)深拷贝、浅拷贝
设计模式_11_原型模式(prototype) 浅拷贝: package designPatternOf23; /** * 定义:用原型实例,指定创建对象的种类,并通过拷贝这些原型创建新的对象 * P ...
- C#设计模式(6)——原型模式(Prototype Pattern)
一.引言 在软件系统中,当创建一个类的实例的过程很昂贵或很复杂,并且我们需要创建多个这样类的实例时,如果我们用new操作符去创建这样的类实例,这未免会增加创建类的复杂度和耗费更多的内存空间,因为这样在 ...
- C#设计模式之六原型模式(Prototype)【创建型】
一.引言 在开始今天的文章之前先说明一点,欢迎大家来指正.很多人说原型设计模式会节省机器内存,他们说是拷贝出来的对象,这些对象其实都是原型的复制,不会使用内存.我认为这是不对的,因为拷贝出来的每一个对 ...
- C#设计模式之五原型模式(Prototype Pattern)【创建型】
一.引言 在开始今天的文章之前先说明一点,欢迎大家来指正.很多人说原型设计模式会节省机器内存,他们说是拷贝出来的对象,这些对象其实都是原型的复制,不会使用内存.我认为这是不对的,因为拷贝出来的每一个对 ...
随机推荐
- aruba 802.11ac协议
上述功能为802.11ac协议,高密环境下建议不勾选. 附百度百科:虽然802.11ac标准草案提高了传输速度并增加了带宽,可以支持企业网络中数量越来越庞大的设备,但是企业开始发现,这个标准需要依赖于 ...
- java_14.1 判断是否是闰年
package demo; import java.util.Calendar; import java.util.Scanner; public class Demo { public static ...
- 使用Python3.x抓取58同城(南京站)的演出票的信息
#!/usr/bin/env python #-*-coding: utf-8 -*- import re import urllib.request as request from bs4 impo ...
- Aspose.Words三 创建表格
创建表格,实现合并行.和并列.表居中.表格水平和垂直居中.设置单元格边框颜色和样式. string templateFile = Server.MapPath("table_templ.do ...
- IDEA配置maven,jdk,编码
1.电脑已解压maven,修改好settings.xml文件,本地仓库,下载远程镜像 2.
- C#百度图片识别API调用返回数据包解析
百度图片识别api接口 public static JObject GeneralBasic(string apikey,string secretkey,string path) { var cli ...
- 78k的text 文件,输出到textbox 竟然用了20几秒的原因
开始查资料以为是io读取的,磁盘速度慢的之类的,后来一想,text 又不是几十万条数据,才那么两千行,咋回事. 原来是循环中不停的修改textbox值导致的. 总结: 比较大的运算,特别是大的循环, ...
- PAT 1089 狼人杀-简单版(20 分)(代码+测试点分析)
1089 狼人杀-简单版(20 分) 以下文字摘自<灵机一动·好玩的数学>:"狼人杀"游戏分为狼人.好人两大阵营.在一局"狼人杀"游戏中,1 号玩家 ...
- 探索未知种族之osg类生物---呼吸分解之advance
回顾 我们用了两节的内容才堪堪讲解完ViewerBase::frame()函数中调用的realize()---Viewer:: realize()函数.我们简单的总结就是Viewer:: realiz ...
- JoyOI1391 走廊泼水节
一道另类生成树 原题链接 将输入的树的\(n-1\)条边按从小到大排序,然后\(Kruskal\)在生成该树的过程中计算新增边的总长. 当在连第\(i\)条边,设该边的两端点为\(x,y\),长度为\ ...