目录
1、核心思想
目的:通过复制(克隆)现有对象来创建新对象,而不是通过new关键字实例化。对于那些有非常复杂的初始化过程的对象或者是需要耗费大量资源的情况,原型模式是更好的选择。
核心价值:通过克隆避免重复初始化,提升性能。
克隆的优势:克隆操作时Java虚拟机会进行内存操作,直接拷贝原型对象数据流生成新的副本对象,绝不会拖泥带水地触发一些多余的复杂操作(如类加载、实例化、初始化等),所以其效率远远高于“new”关键字所触发的实例化操作。
注意:
1> 浅拷贝与深拷贝
浅拷贝:复制原始类型的值,引用类型只拷贝地址引用(指针),与原对象的应用变量地址指向的内存对象是同一个。
深拷贝:需要在clone方法里,自行递归实现引用对象的clone和赋值,确保与原对象完全独立,注意这里的引用对象也需要实现Cloneable接口。递归赋值会大幅增加资源消耗。
2> 依赖 Cloneable
接口:若类未实现 Cloneable
,调用 clone()
会抛出 CloneNotSupportedException。
性能对比:
场景 | new 的消耗 |
clone() 的消耗 |
---|---|---|
简单对象(浅拷贝) | 较高 | 低(跳过构造函数) |
复杂对象(深拷贝) | 高 | 可能更高(递归复制) |
优缺点:
优点 | 缺点 |
---|---|
避免重复初始化,提升性能 | 深拷贝实现复杂(尤其循环引用时) |
动态生成对象配置(修改原型即可) | 需为每个类实现克隆方法 |
隐藏对象创建细节,降低耦合度 | 可能违背构造函数约束(如私有状态) |
2、实现方式
2.1 基本结构
抽象原型接口(Prototype):声明克隆方法(如
clone()
),对应Cloneable接口。具体原型实现类(ConcretePrototype):实现克隆方法,定义如何复制自身,实现方法中调用super.clone()即可得到新的浅克隆的对象。
客户端(Client):通过原型对象的
clone()
方法生成新对象。
2.2 代码示例(Java)
// 1. 抽象原型接口 Cloneable
// 2. 具体原型类
public class ConcretePrototype implements Cloneable {
private String field;
private List<String> listField; // 引用类型字段
private ObjectTmp objectTmp; // 引用类型字段,ObjectTmp类需要实现Cloneable
public ConcretePrototype(String field, List<String> listField) {
this.field = field;
this.listField = listField;
}
publice void setListField(List<String> listField) {
this.listField = listField;
}
publice void setObjectTmp(ObjectTmp objectTmp) {
this.objectTmp= objectTmp;
}
@Override
public ConcretePrototype clone() {
try {
// 浅拷贝(直接复制引用)
ConcretePrototype copy = (ConcretePrototype) super.clone();
// 深拷贝(需手动复制引用类型字段)
copy.setListField(new ArrayList<>(this.listField));
copy.setObjectTmp(this.objectTmp.clone());
return copy;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
// 3. 客户端使用
public class Client {
public static void main(String[] args) {
ConcretePrototype prototype = new ConcretePrototype("value", Arrays.asList("a", "b"));
ConcretePrototype clone = (ConcretePrototype) prototype.clone();
}
}
3、适用场景
对象创建成本高:如需要复杂计算的配置对象。
动态生成对象变体:例如游戏中生成不同属性的敌人。
需要隔离对象状态:保证原对象与新对象互不影响。
结合工厂模式使用:用原型注册表管理多种原型对象。
4、new与clone实际场景建议
优先用
new
:代码更清晰,符合常规对象创建逻辑。
避免深浅拷贝的潜在问题(如意外共享引用)。
谨慎用
clone()
:仅在需要高效复制简单对象时使用(如缓存对象、原型模式)。
确保正确实现
Cloneable
接口并处理深浅拷贝。
替代方案:
工厂方法/构建器模式:灵活控制对象创建流程。
序列化/反序列化:实现深拷贝,但性能较差。
public class DeepCopyUtil {
public static <T extends Serializable> T deepCopy(T object) {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(object);
try (ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis)) {
return (T) ois.readObject();
}
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException("Deep copy failed", e);
}
}
}