原型模式 (Prototype Pattern)
模式定义
原型模式是一种创建型设计模式,通过复制(克隆)已有实例来创建新对象,而不是通过 new 关键字实例化。
核心要点
- 实现
Cloneable接口 - 重写
clone()方法 - 区分浅拷贝和深拷贝
浅拷贝 vs 深拷贝
| 特性 | 浅拷贝 | 深拷贝 |
|---|---|---|
| 基本类型 | 复制值 | 复制值 |
| 引用类型 | 复制引用 | 复制整个对象 |
| 性能 | 快 | 较慢 |
| 安全性 | 可能有副作用 | 更安全 |
实现方式
1. Cloneable 接口(浅拷贝)
java
public class Address implements Cloneable, Serializable {
private String city;
private String street;
public Address(String city, String street) {
this.city = city;
this.street = street;
}
// 实现浅拷贝
@Override
public Address clone() {
try {
return (Address) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
// getter/setter 省略
@Override
public String toString() {
return "Address{city='" + city + "', street='" + street + "'}";
}
}
public class Employee implements Cloneable, Serializable {
private String name;
private double salary;
private Address address; // 引用类型
public Employee(String name, double salary, Address address) {
this.name = name;
this.salary = salary;
this.address = address;
}
// 浅拷贝
@Override
public Employee clone() {
try {
return (Employee) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
// getter/setter 省略
@Override
public String toString() {
return "Employee{name='" + name + "', salary=" + salary +
", address=" + address + '}';
}
}
// 测试浅拷贝
public class ShallowCopyDemo {
public static void main(String[] args) {
Address address = new Address("北京", "朝阳区");
Employee emp1 = new Employee("张三", 10000, address);
// 克隆对象
Employee emp2 = emp1.clone();
System.out.println("修改前:");
System.out.println("emp1: " + emp1);
System.out.println("emp2: " + emp2);
// 修改克隆对象的基本类型
emp2.salary = 20000;
// 修改克隆对象的引用类型
emp2.address.city = "上海";
System.out.println("\n修改后:");
System.out.println("emp1: " + emp1); // address.city 也变成了"上海"
System.out.println("emp2: " + emp2);
// 验证引用是否相同
System.out.println("\n地址是否为同一对象: " +
(emp1.address == emp2.address)); // true,浅拷贝
}
}2. 深拷贝 - 手动实现
java
public class DeepCloneAddress implements Cloneable, Serializable {
private String city;
private String street;
public DeepCloneAddress(String city, String street) {
this.city = city;
this.street = street;
}
@Override
public DeepCloneAddress clone() {
try {
return (DeepCloneAddress) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
// getter/setter 省略
}
public class DeepCloneEmployee implements Cloneable, Serializable {
private String name;
private double salary;
private DeepCloneAddress address;
public DeepCloneEmployee(String name, double salary, DeepCloneAddress address) {
this.name = name;
this.salary = salary;
this.address = address;
}
// 深拷贝 - 手动克隆每个引用类型
@Override
public DeepCloneEmployee clone() {
try {
DeepCloneEmployee cloned = (DeepCloneEmployee) super.clone();
// 对引用类型也进行克隆
cloned.address = this.address.clone();
return cloned;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
@Override
public String toString() {
return "DeepCloneEmployee{name='" + name + "', salary=" + salary +
", address=" + address + '}';
}
}3. 深拷贝 - 序列化实现
通过序列化和反序列化实现完全深拷贝。
java
public class SerializationCopy {
// 通用深拷贝方法
@SuppressWarnings("unchecked")
public static <T extends Serializable> T deepCopy(T object) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(object);
oos.flush();
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (T) ois.readObject();
} catch (Exception e) {
throw new RuntimeException("深拷贝失败", e);
}
}
}
// 使用
// Employee emp2 = SerializationCopy.deepCopy(emp1);
// 注意:所有引用的类都需要实现 Serializable 接口4. 深拷贝 - JSON 序列化
使用 JSON 工具库实现深拷贝(需要额外依赖)。
java
// 使用 Jackson
public class JsonCopy {
private static final ObjectMapper mapper = new ObjectMapper();
@SuppressWarnings("unchecked")
public static <T> T deepCopy(T object, Class<T> clazz) {
try {
String json = mapper.writeValueAsString(object);
return mapper.readValue(json, clazz);
} catch (Exception e) {
throw new RuntimeException("JSON 深拷贝失败", e);
}
}
}
// 使用
// Employee emp2 = JsonCopy.deepCopy(emp1, Employee.class);5. 原型注册表
管理多个原型实例,支持按名称克隆。
java
public class PrototypeRegistry {
// 原型注册表
private static final Map<String, Cloneable> prototypes = new HashMap<>();
// 注册原型
public static void register(String name, Cloneable prototype) {
prototypes.put(name, prototype);
}
// 按名称克隆
@SuppressWarnings("unchecked")
public static <T> T create(String name) {
Cloneable prototype = prototypes.get(name);
if (prototype == null) {
throw new IllegalArgumentException("未找到原型: " + name);
}
return (T) prototype.clone();
}
// 移除原型
public static void remove(String name) {
prototypes.remove(name);
}
}
// 使用
public class PrototypeRegistryDemo {
public static void main(String[] args) {
// 注册原型
PrototypeRegistry.register("employee",
new Employee("默认员工", 5000, new Address("北京", "默认地址")));
PrototypeRegistry.register("manager",
new Employee("默认经理", 15000, new Address("上海", "管理地址")));
// 克隆原型
Employee emp1 = PrototypeRegistry.create("employee");
Employee emp2 = PrototypeRegistry.create("manager");
System.out.println("普通员工: " + emp1);
System.out.println("经理: " + emp2);
}
}JDK 中的原型模式
HashMap.clone()
java
HashMap<String, Integer> original = new HashMap<>();
original.put("key1", 1);
// 浅拷贝
HashMap<String, Integer> cloned = (HashMap<String, Integer>) original.clone();ArrayList.clone()
java
ArrayList<String> list = new ArrayList<>();
list.add("Java");
ArrayList<String> cloned = (ArrayList<String>) list.clone();实际应用
- Spring Bean: prototype 作用域的 Bean 每次请求都克隆一个新实例
- 对象缓存: 缓存中存储原型,需要时克隆
- 配置对象: 从模板配置克隆出多个相似配置
- 图形编辑器: 复制图形对象
- 游戏角色: 克隆角色模板
优缺点
优点:
- 性能好,比
new创建对象快 - 隐藏创建细节
- 可以动态获取对象运行时状态
缺点:
- 深拷贝实现复杂
- 需要实现
Cloneable接口 - 对于包含循环引用的对象,克隆较复杂
注意事项
clone()方法是浅拷贝,需要深拷贝时要手动实现- 引用类型需要额外处理
- 序列化方式实现深拷贝要求所有类实现
Serializable - 原型模式与工厂模式结合使用效果更好