原型模式基础概念
原型模式是一种创建型设计模式,其核心思想是通过复制(克隆)现有对象来创建新对象,而无需依赖显式的类实例化过程。这种模式适用于创建对象成本较高(如初始化时间长、资源消耗大)或需要避免复杂的对象创建逻辑的场景。
原型模式的核心组件
- 原型接口 (Prototype) - 定义克隆方法的接口
- 具体原型类 (ConcretePrototype) - 实现原型接口,提供克隆方法的具体实现
- 客户端 (Client) - 通过调用原型对象的克隆方法来创建新对象
浅克隆与深克隆
在 Java 中,克隆分为两种类型:
浅克隆 (Shallow Clone) - 复制对象时,仅复制对象本身及其基本数据类型字段,而引用类型字段仍指向原对象的引用
- 深克隆 (Deep Clone) - 复制对象时,不仅复制对象本身,还递归复制其引用类型字段,确保新对象和原对象完全独立
原型模式的实现
下面通过示例代码展示原型模式的实现:
import java.util.ArrayList;
import java.util.List;
// 原型接口
interface Prototype {
Prototype clone();
}
// 具体原型类 - 浅克隆示例
class Employee implements Prototype, Cloneable {
private String name;
private int age;
private List<String> skills; // 引用类型字段
public Employee(String name, int age, List<String> skills) {
this.name = name;
this.age = age;
this.skills = skills;
}
// Getters and setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<String> getSkills() {
return skills;
}
public void setSkills(List<String> skills) {
this.skills = skills;
}
// 浅克隆实现
@Override
public Employee clone() {
try {
// 调用Object类的clone()方法进行浅克隆
Employee cloned = (Employee) super.clone();
return cloned;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", skills=" + skills +
'}';
}
}
// 具体原型类 - 深克隆示例
class Department implements Prototype, Cloneable {
private String deptName;
private Employee manager; // 引用类型字段
public Department(String deptName, Employee manager) {
this.deptName = deptName;
this.manager = manager;
}
// Getters and setters
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public Employee getManager() {
return manager;
}
public void setManager(Employee manager) {
this.manager = manager;
}
// 深克隆实现
@Override
public Department clone() {
try {
// 调用Object类的clone()方法进行浅克隆
Department cloned = (Department) super.clone();
// 手动深克隆引用类型字段
if (this.manager != null) {
// 递归克隆manager对象
Employee clonedManager = this.manager.clone();
// 为避免无限递归,需要在Employee类中实现深克隆
// 这里假设Employee类已经正确实现了深克隆
cloned.manager = clonedManager;
}
return cloned;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
@Override
public String toString() {
return "Department{" +
"deptName='" + deptName + '\'' +
", manager=" + manager +
'}';
}
}
// 原型管理器 - 集中管理原型对象
class PrototypeManager {
private static final java.util.Map<String, Prototype> prototypes = new java.util.HashMap<>();
static {
// 初始化一些原型对象
List<String> skills = new ArrayList<>();
skills.add("Java");
skills.add("Spring");
Employee employeePrototype = new Employee("Prototype Employee", 30, skills);
prototypes.put("employee", employeePrototype);
Department deptPrototype = new Department("IT Department", employeePrototype);
prototypes.put("department", deptPrototype);
}
// 获取原型对象的克隆
public static Prototype getClone(String key) {
Prototype prototype = prototypes.get(key);
if (prototype != null) {
return prototype.clone();
}
return null;
}
// 注册新的原型对象
public static void registerPrototype(String key, Prototype prototype) {
prototypes.put(key, prototype);
}
}
// 客户端代码
public class PrototypePatternClient {
public static void main(String[] args) {
// 使用原型管理器获取克隆对象
Employee clonedEmployee = (Employee) PrototypeManager.getClone("employee");
Department clonedDepartment = (Department) PrototypeManager.getClone("department");
System.out.println("Original Employee: " + PrototypeManager.getClone("employee"));
System.out.println("Cloned Employee: " + clonedEmployee);
System.out.println("\nOriginal Department: " + PrototypeManager.getClone("department"));
System.out.println("Cloned Department: " + clonedDepartment);
// 验证浅克隆和深克隆的效果
// 修改克隆对象的基本类型字段
clonedEmployee.setAge(35);
// 修改克隆对象的引用类型字段
List<String> clonedSkills = clonedEmployee.getSkills();
clonedSkills.add("Hibernate");
System.out.println("\nAfter modification:");
System.out.println("Original Employee: " + PrototypeManager.getClone("employee"));
System.out.println("Cloned Employee: " + clonedEmployee);
// 验证深克隆
Employee clonedManager = clonedDepartment.getManager();
clonedManager.setName("New Manager");
System.out.println("\nAfter manager modification:");
System.out.println("Original Department Manager: " + ((Department) PrototypeManager.getClone("department")).getManager().getName());
System.out.println("Cloned Department Manager: " + clonedDepartment.getManager().getName());
}
}
原型模式的应用场景
- 对象创建成本高 - 当对象创建过程复杂或耗时较长时
- 避免重复初始化 - 当需要创建多个相同或相似的对象时
- 动态配置对象 - 当系统需要从现有对象动态生成新对象时
- 缓存原型对象 - 当需要缓存对象状态并在需要时恢复时
原型模式的优缺点
优点:
- 提高性能 - 避免重复创建对象的开销
- 简化对象创建 - 无需了解对象创建的具体细节
- 扩展性好 - 可以在运行时动态添加或删除原型
- 简化复杂对象创建 - 适合创建复杂配置的对象
缺点:
- 实现复杂 - 深克隆的实现可能比较复杂
- 克隆方法维护困难 - 当类的结构发生变化时,需要修改克隆方法
- 对克隆方法的依赖 - 必须实现 Cloneable 接口并重写 clone () 方法
使用原型模式的注意事项
- 正确实现克隆方法 - 确保浅克隆和深克隆的正确实现
- 处理引用类型字段 - 在深克隆中,需要递归克隆所有引用类型字段
- 考虑线程安全 - 如果在多线程环境中使用,需要考虑克隆方法的线程安全性
- 原型管理器的使用 - 对于复杂系统,考虑使用原型管理器集中管理原型对象
- 替代方案 - 在某些情况下,可以考虑使用序列化和反序列化实现深克隆
原型模式是一种非常实用的设计模式,它通过复制现有对象来创建新对象,避免了复杂的对象创建过程,提高了性能和灵活性。在实际开发中,根据对象的复杂度和需求,可以选择浅克隆或深克隆来实现原型模式。