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

一、浅拷贝和深拷贝

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. maven 创建project

    ------------------------------maven3常用命令--------------------------- 1.常用命令 1)创建一个Project mvn archety ...

  2. zabbix基础使用(以思科交换机为例)

    1.创建host group --以方便添加告警和给host分组 一般先创建一个Group-Net,然后根据地点创建.命名,如Group-Net-BeiJing 2.创建Template 1.创建Di ...

  3. 项目总结12:bootstrap-select下拉框模糊搜索

    bootstrap select下拉框模糊搜索 关键字 bootstrap-select 下拉框模糊搜索 正文(直接上源码) <%@ page language="java" ...

  4. LWP::UserAgent的用法

    LWP::UserAgent是一个模拟用户浏览器的类,在使用的时候需要遵守以下几步: 1.引入模块 2.创建一个LWP::UserAgent的对象 3.设置这个对象的相关参数 4.创建HTTP::Re ...

  5. 2019.3.15 关于IE

    1. .clearfix {zoom:1} zoom:1   是ie浏览器专有属性  它可以设置或检索对象缩放比例  处理ie的hasLayout属性  清除浮动  清除margin的重叠

  6. webpack接上一篇

    html-webpack-plugin 自动生成html文件 安装:npm install html-webpack-plugin --save-dev 使用 在webpack.config.js中引 ...

  7. opencv和openGL的关系

    OpenCV是 Open Source Computer Vision Library OpenGL是 Open Graphics Library OpenCV主要是提供图像处理和视频处理的基础算法库 ...

  8. Python爬虫的原理

    简单来说互联网是由一个个站点和网络设备组成的大网,我们通过浏览器访问站点,站点把HTML.JS.CSS代码返回给浏览器,这些代码经过浏览器解析.渲染,将丰富多彩的网页呈现我们眼前: 一.爬虫是什么? ...

  9. 在iOS 8及以后使用UIAlertController 等各种弹出警告通知

    原文转自:在iOS 8中使用UIAlertController 感谢作者分享,自我学习之用 iOS 8的新特性之一就是让接口更有适应性.更灵活,因此许多视图控制器的实现方式发生了巨大的变化.全新的UI ...

  10. Java的OOP三大特征之一——多态

    OOP(面对对象)三大特征之一——多态 What:多态性是指允许不同类的对象对同一消息作出响应,多态性包括参数化多态性和包含多态性,多态性语言具有灵活.抽象.行为共享.代码共享的优势,很好的解决了应用 ...