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. 牛客多校2 D-money(dp记录/贪心)

    D-money 链接:https://www.nowcoder.com/acm/contest/140/D来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K, ...

  2. 使用tomcat作为容器安装Jenkins

    安装前准备环境:jdk,maven,tomcat jdk 参考centos安装jdk:https://www.cnblogs.com/pipiyan/p/10491876.html maven 已有安 ...

  3. IT兄弟连 JavaWeb教程 使用AJAX发送GET请求并获取响应

    GET请求用于获取数据,有时候我们需要获取的数据需要通过"查询参数"进行定位,在这种情况下,我们会将查询参数追加到URL的末尾,令服务器解析. 使用Ajax发送GET请求非常简单, ...

  4. tableview中用动画效果改变cell的高度

    我们要的效果大概就是如下效果: 当我们选择一个cell的时候,我们就要改变它的高度,并且以动画的形式. 我们该如何实现这个效果呢?我们主要需要使用以下这两个方法: - (CGFloat)tableVi ...

  5. Solidity 最新 0.5.8 中文文档发布

    本文首发于深入浅出区块链社区 热烈祝贺 Solidity 最新 0.5.8 中文文档发布, 这不单是一份 Solidity 速查手册,更是一份深入以太坊智能合约开发宝典. 翻译说明 Solidity ...

  6. EOS帐户交易的构建命令

    EOS版本:4.0   系统:Ubuntu 16.04 LTS   1.创建两对密匙   cleos create key   Private key:5JeTwSwKfpVRHGLqysakTXfk ...

  7. 黑马学习AJAX jQuery发送异步请求 $.ajax() $.post() $.get()是在调用方法而不是定义方法

  8. 架构sass文件

    sass/ | |– base/ | |– _reset.scss # Reset/normalize | |– _typography.scss # Typography rules | ... # ...

  9. Codeforces Round #433 (Div. 2, based on Olympiad of Metropolises) D

    Country of Metropolia is holding Olympiad of Metrpolises soon. It mean that all jury members of the ...

  10. Floyd判圈法

    ---恢复内容开始--- http://blog.csdn.net/ruoruo_cheng/article/details/53100656 ---恢复内容结束---