Java 的设计模式有 23 种,前段时间小编已经介绍了单例模式,由于我们在学习 Spring 的时候在 bean 标签的学习中碰到了今天要讲的原型模式,那么小编就已本文来介绍下原型模式。

原型模式
  在java中我们知道通过new关键字创建的对象是非常繁琐的(类加载判断,内存分配,初始化等),在我们需要大量对象的情况下,原型模式就是我们可以考虑实现的方式。
  原型模式我们也称为克隆模式,即一个某个对象为原型克隆出来一个一模一样的对象,该对象的属性和原型对象一模一样。而且对于原型对象没有任何影响。原型模式的克隆方式有两种:浅克隆和深度克隆

浅克隆
  在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。

  简单来说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。

实现
被克隆的对象必须Cloneable,Serializable这两个接口
原型类

/**
* 原型类:被克隆的类型
*/
public class User implements Cloneable, Serializable {

private String name;

private Date birth;

private int age;

/**
* 实现克隆的方法
* @return
* @throws CloneNotSupportedException
*/
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
//此处略过get和set方法
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
测试类

public static void main(String[] args) throws CloneNotSupportedException {
Date date = new Date(1231231231231l);
User user = new User();
user.setName("zmf");
user.setAge(18);
user.setBirth(date);
System.out.println("----输出原型对象的属性------");
System.out.println(user);
System.out.println(user.getName());
System.out.println(user.getBirth());
// 克隆对象
User user1 =(User) user.clone();
// 修改原型对象中的属性
date.setTime(123231231231l);
System.out.println("原型对象修改后的属性:" + user.getBirth());

// 修改参数
user1.setName("知性人");
System.out.println("-------克隆对象的属性-----");
System.out.println(user1);
System.out.println(user1.getName());
System.out.println(user1.getBirth());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
输出结果:

----输出原型对象的属性------
org.zmf.User@1b6d3586
zmf
Tue Jan 06 16:40:31 CST 2009
原型对象修改后的属性:Tue Nov 27 14:53:51 CST 1973
-------克隆对象的属性-----
org.zmf.User@14ae5a5
知性人
Tue Nov 27 14:53:51 CST 1973
1
2
3
4
5
6
7
8
9
说明:克隆后的 date 属性和原型对象修改后的 date 属性的结果一样 说明两个对象的Date的引用是同一个。由此可以说明,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。

深克隆
  在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。

  简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将复制。

深度克隆(deep clone)有两种实现方式,第一种是在浅克隆的基础上实现,第二种是通过序列化和反序列化实现,我们分别来介绍
1
第一种方式
在浅克隆的基础上实现
原型类

/**
* 原型类:被克隆的类型
* 深度克隆测试
*/
public class User2 implements Cloneable, Serializable {

private String name;

private Date birth;

private int age;

/**
* 实现克隆的方法
* 深度克隆(deep clone)
*/
public Object clone() throws CloneNotSupportedException{
Object object = super.clone();
// 实现深度克隆(deep clone)
User2 user = (User2)object;
user.birth = (Date) this.birth.clone();
return object;
}
//此处略过 get 和 set 方法
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
测试类:

public static void main(String[] args) throws CloneNotSupportedException {
Date date = new Date(1231231231231l);
User2 user = new User2();
user.setName("zmf");
user.setAge(18);
user.setBirth(date);
System.out.println("----输出原型对象的属性------");
System.out.println(user);
System.out.println(user.getName());
System.out.println(user.getBirth());
// 克隆对象
User2 user1 =(User2) user.clone();
// 修改原型对象中的属性
date.setTime(123231231231l);
System.out.println("原型对象修改后的属性:" + user.getBirth());
// 修改参数
user1.setName("知性人");
System.out.println("-------克隆对象的属性-----");
System.out.println(user1);
System.out.println(user1.getName());
System.out.println(user1.getBirth());

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
测试结果:

----输出原型对象的属性------
org.zmf.User2@1b6d3586
zmf
Tue Jan 06 16:40:31 CST 2009
原型对象修改后的属性:Tue Nov 27 14:53:51 CST 1973
-------克隆对象的属性-----
org.zmf.User2@14ae5a5
知性人
Tue Jan 06 16:40:31 CST 2009
1
2
3
4
5
6
7
8
9
说明:根据测试得出克隆后的对象的属性并没有随着我们对原型对象Date属性的修改而改变,说明克隆对象的Date属性和原型对象的Date属性引用的不是同一个对象,实现的深度复制。

第二种方式:序列化和反序列化
说明
序列化: 把对象转换为字节序列的过程。
反序列化: 把字节序列恢复为对象的过程。
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
Date date = new Date(1231231231231L);
User user = new User();
user.setName("zmf");
user.setAge(18);
user.setBirth(date);
System.out.println("-----原型对象的属性------");
System.out.println(user);
System.out.println(user.getName());
System.out.println(user.getBirth());

//使用序列化和反序列化实现深复制
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(user);
byte[] bytes = bos.toByteArray();

ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);

//克隆好的对象!
User user1 = (User) ois.readObject();

// 修改原型对象的值
date.setTime(221321321321321L);
System.out.println(user.getBirth());

System.out.println("------克隆对象的属性-------");
System.out.println(user1);
System.out.println(user1.getName());
System.out.println(user1.getBirth(http://www.my516.com));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
测试结果:

-----原型对象的属性------
org.zmf.User@1b6d3586
zmf
Tue Jan 06 16:40:31 CST 2009
Sat May 24 16:48:41 CST 8983
------克隆对象的属性-------
org.zmf.User@5f184fc6
zmf
Tue Jan 06 16:40:31 CST 2009
1
2
3
4
5
6
7
8
9
实现了和第一种实现方式相同的效果~实现了深度克隆

总结
实现对象克隆有两种方式:

 1). 实现Cloneable接口并重写Object类中的clone()方法;

 2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。
---------------------

Java 原型模式(克隆模式)的更多相关文章

  1. [19/04/24-星期三] GOF23_创建型模式(建造者模式、原型模式)

    一.建造者模式 本质:分离了对象子组件的单独构造(由Builder负责)和装配的分离(由Director负责),从而可以构建出复杂的对象,这个模式适用于:某个对象的构建过程十分复杂 好处:由于构建和装 ...

  2. Java原型模式

    原型模式 原型模式也称克隆模式.原型模式jian ming zhi yi,就是先创造出一个原型,然后通过类似于Java中的clone方法,对对象的拷贝,克隆类似于new,但是不同于new.new创造出 ...

  3. JAVA 23种开发模式详解(代码举例)

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  4. java设计模式5--原型模式(Prototype)

    本文地址:http://www.cnblogs.com/archimedes/p/java-prototype-pattern.html,转载请注明源地址. 原型模式 用原型实例指定创建对象的种类,并 ...

  5. java的23中设计模式

    一.设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接 ...

  6. Java经典23创意模式设计模式(两)

    本文介绍5其余两种创意模式:模型构建器(Builder).原型模型(PROTOTYPE). 一.建造者模式(别名:生成者模式) 将复杂对象的构建和它的表示分离,使得相同的构建过程能够创建不同的表示. ...

  7. 折腾Java设计模式之备忘录模式

    原文地址:折腾Java设计模式之备忘录模式 备忘录模式 Without violating encapsulation, capture and externalize an object's int ...

  8. java运行时内存模式学习

    学习java运行时内存模式: 各区介绍: 方法区(线程共享):用于存放被虚拟机加载的类的元数据:静态变量,常量,以及编译和的代码(字节码),也称为永久代(所有该类的实例被回收,或者此类classLoa ...

  9. Java设计模式——装饰者模式

    JAVA 设计模式 装饰者模式 用途 装饰者模式 (Decorator) 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活. 装饰者模式是一种结构式模式 ...

随机推荐

  1. 洛谷P3379 【模板】最近公共祖先(LCA)(dfs序+倍增)

    P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询 ...

  2. Linux 之添加系统环境变量

    PATH 值是一系列目录,当执行命令时,linux就在这些目录下查找,其格式为: PATH=$PATH:<PATH1>:<PATH2>:<PATH3>:------ ...

  3. window.onerror 捕捉所有的前端error

    //[捕捉所有前端error] window.onerror = function (errormessage, url, line, column, error) { console.log(&qu ...

  4. ssm重新开发计科院新闻网站

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"% ...

  5. 【转】PHP实现下载与压缩文件的封装与整理

    [转]PHP实现下载与压缩文件的封装与整理    https://mp.weixin.qq.com/s/BUI3QsdNi6Nqu0NhrUL8hQ 一.PHP实现打包zip并下载功能 $file_t ...

  6. Linux运用一些常用命令

    今天搜集整理了一些Linux服务器运维常用命令,希望对大家有帮助:1.删除0字节文件 find -type f -size 0 -exec rm -rf {} 2.查看进程按内存从大到小排列 ps - ...

  7. uoj#279. 【UTR #2】题目交流通道(容斥+数数)

    传送门 先考虑无解的情况,为以下几种:\(dis_{i,j}+dis_{j,k}<dis_{i,k}\),\(dis_{i,i}\neq 0\),\(dis_{i,j}\neq dis_{j,i ...

  8. 关于c语言中的字符串的问题

      静态数组,动态数组,链表是c语言中处理存储数据最基本的三种方式. 1.静态数组,你先定好大小,直接赋值即可,不要超过定义的长度. 2.动态分配数组,在执行的时候,输入要分的内存大小,然后p=(vo ...

  9. IT兄弟连 Java语法教程 Java语言背景

    驱使计算机语言革新的因素有两个:程序设计技术的改进和计算环境的改变.Java也不例外.在大量继承C和C++的基础之上,Java还增加了反应当前程序设计技术状态的功能与精华.针对在线环境的蓬勃发展(In ...

  10. python3 安装虚拟镜像

    virtualenvwrapper--提供了一系列命令使得和虚拟环境工作变得愉快很多,他把你所需要的虚拟环境都放在一个地方. 1.先安装virtualenv:pip install virtualen ...