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

一、浅拷贝和深拷贝

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. ajax请求跨域

    解决方式 1: 解决方式 2: 服务端: package ceshi_utils; import java.util.*; import com.xwhb.utils.encrypt.CipherUt ...

  2. [剑指Offer]23-链表中环的入口节点

    题目链接 https://www.nowcoder.com/practice/253d2c59ec3e4bc68da16833f79a38e4?tpId=13&tqId=11208&t ...

  3. pa sslvpn配置

    1.新建隧道接口 2.新建区域,并将该区域与上一步中的隧道接口关联 3.新建本地证书及配置文件 (1) 常见名称处填写防火墙外网口IP. 添加成功后的证书信息如下: 2)新建SSL/TLS服务配置文件 ...

  4. crm作业知识点集合[一]

    知识点1 1.当我们通过model建立一对多或者多对多的关系的时候,默认情况下,会关联所有的字段,如果我们使用djanog的forms的话,可以加一个属性,限制我这个字段只关联哪些字段,就是用下面的写 ...

  5. Android的事件分发机制

    public boolean dispatchTouchEvent(MotionEvent event) 通过方法名我们不难猜测,它就是事件分发的重要方法.那么很明显,如果一个MotionEvent传 ...

  6. HTML转义字符 Unicode和CSS伪类介绍

    CSS 伪类用于向某些选择器添加特殊的效果. a:link {color: #FF0000} /* 未访问的链接 */ a:visited {color: #00FF00} /* 已访问的链接 */ ...

  7. go流程控制与函数

    package main; import ( "fmt" ); func main() { isRun := true; //条件判断 if isRun { fmt.Printf( ...

  8. Hibernate: save, persist, update, merge, saveOrUpdate[z]

    [z]https://www.baeldung.com/hibernate-save-persist-update-merge-saveorupdate 1. Introduction In this ...

  9. 关于控制反转(IOC)容器 ,依赖注入(DI)模式必读文章收集

    推荐一篇国外設計大師Martin Fowler的大作:Inversion of Control Containers and the Dependency Injection pattern http ...

  10. 免费证书https://lamp.sh/ssl.html

    https(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的 http 通道,简单讲是 http 的安全版.即 ht ...