在说原型模式之前先说一下浅拷贝深拷贝的概念

一、浅拷贝和深拷贝

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常用设计模式三:原型模式的更多相关文章

  1. Java设计模式05:常用设计模式之原型模式(创建型模式)

    1. Java之原型模式(Prototype Pattern)     原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象. ...

  2. java常用设计模式总览

    一.java的设计模式大体上分为三大类: 创建型模式(5种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式. 结构型模式(7种):适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组 ...

  3. JAVA 设计模式之原型模式

    目录 JAVA 设计模式之原型模式 简介 Java实现 1.浅拷贝 2.深拷贝 优缺点说明 1.优点 2.缺点 JAVA 设计模式之原型模式 简介 原型模式是六种创建型设计模式之一,主要应用于创建相同 ...

  4. java设计模式4——原型模式

    java设计模式4--原型模式 1.写在前面 本节内容与C++语言的复制构造函数.浅拷贝.深拷贝极为相似,因此建议学习者可以先了解C++的该部分的相关知识,或者学习完本节内容后,也去了解C++的相应内 ...

  5. 设计模式之 原型模式详解(clone方法源码的简单剖析)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 原型模式算是JAVA中最简单 ...

  6. 设计模式_11_原型模式(prototype)深拷贝、浅拷贝

    设计模式_11_原型模式(prototype) 浅拷贝: package designPatternOf23; /** * 定义:用原型实例,指定创建对象的种类,并通过拷贝这些原型创建新的对象 * P ...

  7. C#设计模式(6)——原型模式(Prototype Pattern)

    一.引言 在软件系统中,当创建一个类的实例的过程很昂贵或很复杂,并且我们需要创建多个这样类的实例时,如果我们用new操作符去创建这样的类实例,这未免会增加创建类的复杂度和耗费更多的内存空间,因为这样在 ...

  8. C#设计模式之六原型模式(Prototype)【创建型】

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

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

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

随机推荐

  1. 【Linux 线程】线程同步《三》

    1.条件变量 条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起:另一个线程使"条件成立"(给出条 ...

  2. [leetcode]300. Longest Increasing Subsequence最长递增子序列

    Given an unsorted array of integers, find the length of longest increasing subsequence. Example: Inp ...

  3. golang 实现延迟消息原理与方法

    实现延迟消息具体思路我是看的下面这篇文章 https://mp.weixin.qq.com/s/eDMV25YqCPYjxQG-dvqSqQ 实现延迟消息最主要的两个结构: 环形队列:通过golang ...

  4. VML、SVG、Canvas简介

    1.VML: VML的全称是Vector Markup Language(矢量可标记语言),矢量的图形,意味着图形可以任意放大缩小而不损失图形的质量,这在制作地图上有很大用途,VML只是被IE支持. ...

  5. .net core和.net 4.7区别和联系笔记

    1. 简单说,都是.net standard所定义的接口的实现,都是 .net standard的儿子. 3down voteaccepted C# is a programming language ...

  6. Repeater控件添加序号列

    在项目开发过程中,会经常遇到ASP.NET repeater控件添加序号列,有些新手可能还不会,网上搜集整理了一些,需要的朋友可以参考下 ASP.NET repeater添加序号列的方法 1.< ...

  7. MSDos

    一.简介   二.源码 http://www.computerhistory.org/atchm/microsoft-research-license-agreement-msdos-v1-1-v2- ...

  8. js的RegExp

    正则表达式是一种用来匹配字符串的强有力的武器.它的设计思想是用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符串,我们就认为它“匹配”了,否则,该字符串就是不合法的. 所以我们判断一个字符串 ...

  9. C++中string类

    https://blog.csdn.net/sinat_36184075/article/details/54836053 https://blog.csdn.net/fdqw_sph/article ...

  10. OpenGL3D图形、旋转、纹理、键盘移动、光照、滤波、透明(完整) 转自http://www.cnblogs.com/tiandsp/archive/2012/01/23/2329049.html

    #include <windows.h> // Windows的头文件 #include <stdio.h> #include <gl\gl.h> // OpenG ...