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)【创建型】
一.引言 在开始今天的文章之前先说明一点,欢迎大家来指正.很多人说原型设计模式会节省机器内存,他们说是拷贝出来的对象,这些对象其实都是原型的复制,不会使用内存.我认为这是不对的,因为拷贝出来的每一个对 ...
随机推荐
- TZOJ 1210 The area(微积分)
描述 Ignatius bought a land last week, but he didn't know the area of the land because the land is enc ...
- c++笔试题贪吃蛇问题
贪吃蛇 现在有一个N*M(N,M=100)的方形矩形,在这个矩形的每一个方格上都放有一个随机值,一条可爱的小蛇从矩形的 左上角开始出发,每次移动都只能移动一格,向右或向下,而每到达一格贪吃的小蛇都会吧 ...
- Python: 爬取百度贴吧图片
练习之代码片段,以做备忘: # encoding=utf8 from __future__ import unicode_literals import urllib, urllib2 import ...
- web项目no such method exception
昨天更新包后出现这个异常,经过仔细全面排查,项目源码是没问题的. 怀疑jvm被重写了,肉眼也没找到证据.怀疑是操作系统问题,这个也不会没办法排查 于是给客户重新发了个war包,客户运行后出现 异常: ...
- Word打开时显示*模板*,删除模板
XP系统, 找到目录 C:\Documents and Settings\Administrator\Application Data\Microsoft\Templates 删除里面的模板文件即可
- Spring事务<tx:annotation-driven/>的理解
在使用Spring的时候,配置文件中我们经常看到 annotation-driven 这样的注解,其含义就是支持注解,一般根据前缀 tx.mvc 等也能很直白的理解出来分别的作用. <tx:an ...
- [z]c++ 和 java 利用protobuf 通讯
[z]http://andinker.iteye.com/blog/1979428 java端的具体步骤如下: 1.首先下载 下载protobuf 编译工具 http://code.google ...
- Python 内置函数 memoryview
转载自:https://www.cnblogs.com/sesshoumaru/p/6035548.html 英文文档: class memoryview(obj) memoryview object ...
- mysql技术内幕之常规使用
mysql中:终止语句方法: 1.在语句结尾处,输入分号(:)表示语句到此结束 2.使用\g(意思是go) \G以垂直的方式显示结果,每行显示一个值 数据库:数据库中包含表,对表中数据执行插入,检索, ...
- 哪些intel 网卡支持SR-IOV
哪些英特尔®以太网适配器和控制器支持 SR-IOV? 英特尔®以太网融合网络适配器 X710 系列 英特尔®以太网聚合网络适配器 X710-da2 英特尔®以太网聚合网络适配器 X710-da4 英特 ...