定义
指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
不需要知道任何创建的细节,不调用构造函数
类型:创建型
适用场景
- 类初始化消耗较多资源
- new产生的一个对象需要非常繁琐的过程(数据准备、访问权限等
- 构造函数比较复杂
- 循环体中生产大量对象时
优缺点
- 优点
- 原型模式性能比直接new一个对象性能高
- 简化创建过程
- 缺点
- 必须配备克隆方法(实现Cloneable接口(标记型接口))
- 对克隆复杂对象或对克隆出的对象进行复杂改造时,容易引入风险
- 对复杂对象向深拷贝、浅拷贝要运用得当
项目实战
浅克隆
shallow clone,浅克隆是指拷贝对象时仅仅copy对象本身和对象中的基本变量,而不拷贝对象包含的引用类型对象(通过 class 定义的类型等),如Date、Integer等。
实现Cloneable接口
Cloneable是一个标记接口,没有任何方法;在Object类中有clone的实现。
package net.gaox.exercise.clone;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.util.Date;
/**
* <p> </p>
*
* @author gaox·Eric
* @site gaox.net
* @date 2019/11/30 15:19
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Audi implements Cloneable {
/**
* 品牌
*/
private String brand;
/**
* 出厂时间
*/
private Date productionTime;
/**
* 价格
*/
private BigDecimal price;
//这里重写clone方法,使用父类的clone方法
@Override
protected Audi clone() throws CloneNotSupportedException {
return (Audi) super.clone();
}
}
但是发现克隆出的对象与原对象的内存地址不同,但是Date的对象是相同的,结果造成修改其中一个伤害到另外一个的安全性。。
深克隆
深克隆(deep clone )不仅copy对象本身,而且copy对象包含的引用指向的所有对象。
举例:对象X中包含对Y的引用,Y中包含对Z的引用。浅拷贝X得到X1,X1中依然包含对Y的引用,Y中依然包含对Z的引用。深拷贝则是对浅拷贝的递归,深拷贝X得到X1,X1中包含对Y1(Y的copy)的引用,Y1中包含对Z1(Z的copy)的引用。
重新写克隆方法,对于简单类型可以很方便的克隆,对于引用类型最好还是使用深克隆! ! !
package net.gaox.exercise.clone;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.util.Date;
/**
* <p> 红旗汽车 </p>
*
* @author gaox·Eric
* @site gaox.net
* @date 2019/11/30 13:39
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class HongQi implements Cloneable {
/**
* 品牌
*/
private String brand;
/**
* 出厂时间
*/
private Date productionTime;
/**
* 价格
*/
private BigDecimal price;
@Override
protected Object clone() throws CloneNotSupportedException {
HongQi obj = (HongQi) super.clone();
//这里需要对本对象的属性进行深克隆
obj.productionTime = (Date) obj.productionTime.clone();
return obj;
}
}
对比
- 红色线框中是Audi类,克隆之后时间依然指向了同一个对象,可能在后期对我们的程序产生影响。
- 绿色线框中是HongQi类,克隆的时间指向不同的对象,避免程序被破坏。
细心的朋友可能还注意到了,价格price属性在克隆前后还是指向的同一个对象,为什么不一同将其克隆重新赋值呢? 在JDK8中BigDecimal继承自Number,也是不可变类型,对其操作就会返回一个新的对象,不影响我们程序的健壮性。
增加对BigDecimal的扩充克隆
@Override
protected HongQi clone() throws CloneNotSupportedException {
HongQi obj = (HongQi) super.clone();
//这里需要对本对象的属性进行深克隆
obj.productionTime = (Date) obj.productionTime.clone();
obj.price = new BigDecimal(obj.price.toString());
return obj;
}