1. 原型模式
1.1 介绍
指用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。常用于创建某对象的代价比较大时,例如一个对象需要在一个高代价的数据库操作之后被创建。
原型模式的克隆分为浅克隆和深克隆
- 浅克隆:创建一个新对象,只负责克隆按值传递的数据(比如基本数据类型、String类型),而对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。Java中浅克隆必须实现
Cloneable
接口 - 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。深克隆可通过序列化/反序列化,但克隆对象及克隆对象引用的对象必须实现序列化接口
1.2 优缺点
优点
- 创建对象的性能提高
- 无需调用构造函数
缺点
- 配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候
- 必须实现Cloneable接口
1.3 使用场景
-
资源优化场景,
-
类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等
-
性能和安全要求的场景。
-
通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
-
一个对象多个修改者的场景
1.4 注意事项
- 与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 Cloneable并重写Clone方法,调用的是底层JNI方法,深拷贝是通过实现 Serializable 读取二进制流。
2. 案例代码
现在,汽车工厂新建汽车需要多层审批,为了加载建造过程,我们通过复制原有的汽车实现增产。
abstract class CarMat {
abstract String getName();
}
public class AudiCarMat extends CarMat implements Serializable {
@Override
String getName() {
return "奥迪车垫";
}
}
abstract class CarWheel {
abstract String getName();
}
class AudiCarWheel extends CarWheel implements Serializable {
@Override
String getName() {
return "奥迪轮子";
}
}
public class Car implements Cloneable, Serializable {
CarWheel wheel;
CarMat mat;
public void setWheel(CarWheel wheel) {
this.wheel = wheel;
}
public void setMat(CarMat mat) {
this.mat = mat;
}
public CarWheel getWheel() {
return wheel;
}
public CarMat getMat() {
return mat;
}
// 浅拷贝通过JNI实现,要求必须实现Cloneable接口
public static Car shallowClone(Car car) {
Car carClone = null;
try {
carClone = (Car)car.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return carClone;
}
// 深拷贝通过序列化实现,要求必须实现Serializable接口
public static Car deepClone(Car car) {
ObjectOutputStream oos = null;
Car carClone = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("temp"));
oos.writeObject(car);
oos.flush();
oos.close();
ObjectInputStream ios = new ObjectInputStream(new FileInputStream("temp"));
carClone = (Car)ios.readObject();
ios.close();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return carClone;
}
}
/**
* 原型模式
*
*@Author cly
*@Date 2021/08/31 1:24
*@Version 1.0
*/
public class Prototype {
public static void main(String[] args) {
Car car = new Car();
car.setMat(new AudiCarMat());
car.setWheel(new AudiCarWheel());
// 浅拷贝
Car cloneCar = Car.shallowClone(car);
System.out.println(car.mat == cloneCar.mat); //true
System.out.println(car.wheel == cloneCar.wheel);//true
// 深拷贝
Car deepClone = Car.deepClone(car);
System.out.println(car.mat == deepClone.mat); // false
System.out.println(car.wheel == deepClone.wheel);// false
}
}
3. 源码实现
3.1 java.lang.object
在 JDK 中所有类的默认父类 java.lang.Object 中的 clone 方法,就实现快速地浅拷贝一个对象,当然有个前提条件,就是被克隆的对象的类需要实现 Cloneable 接口,否则会抛出异常 CloneNotSupportedException。
/**
* Creates and returns a copy of this object. The precise meaning
* of "copy" may depend on the class of the object.
*/
protected native Object clone() throws CloneNotSupportedException;