原型模式(Prototype Pattern) ,是 GoF 的 23 种设计模式的一种,是用于创建重复的对象,同时又能保证性能。属于创建型模式,提供创建对象的最佳方式。 原型(Prototype),在制造业中通常是指大批量生产开始之前研发出的概念模型,并基于各种参数指标对其进行检验,如果达到了质量要求,即可参照这个原型进行批量生产。原型模式达到以原型实例创建副本实例的目的即可,并不需要知道其原始类,也就是说,原型模式可以用对象创建对象,而不是用类创建对象,以此达到效率的提升。 ~ 本篇内容包括:关于原型模式、原型模式-浅拷贝实现、原型模式-深拷贝实现
文章目录- 一、关于原型模式
- 1、关于原型模式
- 2、关于原型模式的构成
- 3、浅拷贝与深拷贝
- 1、关于原型模式
- 2、关于原型模式的构成
- 3、浅拷贝与深拷贝
- 二、原型模式-浅拷贝实现
- 1、浅拷贝
- 2、浅拷贝实现
- 三、原型模式-深拷贝实现
- 1、深拷贝
- 2、深拷贝实现(序列化方式)
一、关于原型模式
1、关于原型模式
原型模式(Prototype Pattern) ,是 GoF 的 23 种设计模式的一种,是用于创建重复的对象,同时又能保证性能。属于创建型模式,提供创建对象的最佳方式。
原型(Prototype),在制造业中通常是指大批量生产开始之前研发出的概念模型,并基于各种参数指标对其进行检验,如果达到了质量要求,即可参照这个原型进行批量生产。原型模式达到以原型实例创建副本实例的目的即可,并不需要知道其原始类,也就是说,原型模式可以用对象创建对象,而不是用类创建对象,以此达到效率的提升。
2、关于原型模式的构成
原型模式包含如下角色:
- 抽象原型类(Prototype):规定了具体原型对象必须实现的 clone() 方法。抽象原型类是定义具有克隆自己的方法接口,是所有具体原型类的公共父类,可以是抽象类,也可以是接口。
- 具体原型类(ConcretePrototype):实现抽象原型类的 clone() 方法,它是可被复制的对象。
- 访问类(Client):使用具体原型类中的 clone() 方法来复制新的对象。
3、浅拷贝与深拷贝
原型模式的使用需要注意浅拷贝与深拷贝的问题
- 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
- 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
二、原型模式-浅拷贝实现
1、浅拷贝
浅拷贝,即调用 clone 对象拷贝内存中的数据时,要注意拷贝的是基础数据类型,对于数组,集合,自定义类等引用数据类型仅拷贝地址,会造成所有的对象都持有同一个内存地址的引用成员。
- 基础数据类型:如果类中全部是基础数据类型,使用 clone 可以将该类完整的复制一份;
- 引用数据类型:如果类中有引用类型成员,只是拷贝该成员的地址,所有的拷贝创建的原型模式实例对象都持有同一个引用,如果修改该引用成员的值,所有的原型对象实例的值都会跟着修改;
2、浅拷贝实现
# Cloneable 抽象原型类
Java 中的 Object 类中提供了 clone() 方法来实现浅克隆。 Cloneable 接口是可以看作抽象原型类,而实现了 Cloneable 接口的子实现类就是具体的原型类
# Realizetype 具体原型类
代码语言:javascript复制public class Realizetype implements Cloneable {
private Integer a;
private Integer b;
public Integer getA() {
return a;
}
public void setA(Integer a) {
this.a = a;
}
public Integer getB() {
return b;
}
public void setB(Integer b) {
this.b = b;
}
public Realizetype() {
System.out.println("具体的原型对象创建完成!");
}
@Override
protected Realizetype clone() throws CloneNotSupportedException {
System.out.println("具体原型复制成功!");
return (Realizetype) super.clone();
}
}
# Client 访问测试类
代码语言:javascript复制public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Realizetype r1 = new Realizetype();
r1.setA(10);
r1.setB(11);
Realizetype r2 = r1.clone();
// 两者数据分别为 false 和 true 对象都持有同一个内存地址的引用成员
System.out.println("对象r1和r2是同一个对象?" (r1 == r2));
System.out.println("对象r1和r2是同一个对象?" (r1.getA() == r2.getA()));
}
}
三、原型模式-深拷贝实现
1、深拷贝
深拷贝,深拷贝时需要在 clone 方法中 , 调用引用数据类型本身的 clone 对象 , 在将其赋值给被拷贝的原型模式实例对象。
实现深拷贝有两种方法:
- 序列化该对象,然后反序列化回来,就能得到一个新的对象了。 序列化:将对象写入到IO流中; 反序列化:从IO流中恢复对象 序列化机制允许将实现序列化的java对象转化为字节序列,这些字节序列可以保存到磁盘或者网络传输上,以达到以后恢复成原来的对象,序列化机制使得对象可以脱离程序的运行而独立存在。
- 继续利用
clone()
方法,对该对象的引用类型变量再实现一次clone()
方法。
2、深拷贝实现(序列化方式)
这里我们使用序列化的方式来实现深拷贝
# Realizetype 实现 Serializable 序列化接口
# Client
代码语言:javascript复制import java.io.*;
public class Client {
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
Realizetype r1 = new Realizetype();
r1.setA(10);
r1.setB(11);
//创建对象输出流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("/Users/lizhengi/test/b.txt"));
//将c1对象写出到文件中
oos.writeObject(r1);
oos.close();
//创建对象出入流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/Users/lizhengi/test/b.txt"));
//读取对象
Realizetype r2 = (Realizetype) ois.readObject();
// 两者数据都为 false 说明对象持有不同的内存地址的引用成员,完成深拷贝
System.out.println("对象r1和r2是同一个对象?" (r1 == r2));
System.out.println("对象r1和r2是同一个对象?" (r1.getA() == r2.getA()));
}
}