本文目录导读:

我来为你展示一个完整的原型模式深克隆案例,以员工信息管理系统为例:
案例:员工档案管理系统
基础类定义
import java.io.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
// 地址类(引用类型)
class Address implements Serializable {
private String province;
private String city;
private String detail;
public Address(String province, String city, String detail) {
this.province = province;
this.city = city;
this.detail = detail;
}
// getter/setter
public String getProvince() { return province; }
public void setProvince(String province) { this.province = province; }
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
public String getDetail() { return detail; }
public void setDetail(String detail) { this.detail = detail; }
@Override
public String toString() {
return province + "省" + city + "市" + detail;
}
}
// 部门类(引用类型)
class Department implements Serializable {
private String name;
private String manager;
public Department(String name, String manager) {
this.name = name;
this.manager = manager;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getManager() { return manager; }
public void setManager(String manager) { this.manager = manager; }
@Override
public String toString() {
return name + "(负责人:" + manager + ")";
}
}
员工类(实现深克隆)
// 员工类 - 实现深克隆
class Employee implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
// 基本类型
private String name;
private int age;
private double salary;
private Date hireDate;
// 引用类型
private Address address;
private Department department;
private List<String> skills; // 可变引用类型
public Employee(String name, int age, double salary, Date hireDate,
Address address, Department department, List<String> skills) {
this.name = name;
this.age = age;
this.salary = salary;
this.hireDate = hireDate;
this.address = address;
this.department = department;
this.skills = skills;
}
/**
* 方式一:通过重写clone方法实现深克隆
*/
@Override
public Employee clone() throws CloneNotSupportedException {
// 1. 首先调用父类的clone方法(浅克隆)
Employee cloned = (Employee) super.clone();
// 2. 对引用类型字段进行深克隆(手动一个个克隆)
cloned.address = new Address(
this.address.getProvince(),
this.address.getCity(),
this.address.getDetail()
);
cloned.department = new Department(
this.department.getName(),
this.department.getManager()
);
cloned.hireDate = (Date) this.hireDate.clone();
// 3. 对集合进行深克隆
if (this.skills != null) {
cloned.skills = new ArrayList<>(this.skills);
}
return cloned;
}
/**
* 方式二:通过序列化实现深克隆
* 优点:不需要手动逐个处理所有引用字段
*/
public Employee deepCloneBySerialization() {
try {
// 序列化到内存
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 反序列化对象
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (Employee) ois.readObject();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// 用于测试:修改引用对象的属性
public void modifyAddress(String detail) {
this.address.setDetail(detail);
}
public void addSkill(String skill) {
if (this.skills == null) {
this.skills = new ArrayList<>();
}
this.skills.add(skill);
}
// getter/setter方法
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 double getSalary() { return salary; }
public void setSalary(double salary) { this.salary = salary; }
public Date getHireDate() { return hireDate; }
public void setHireDate(Date hireDate) { this.hireDate = hireDate; }
public Address getAddress() { return address; }
public void setAddress(Address address) { this.address = address; }
public Department getDepartment() { return department; }
public void setDepartment(Department department) { this.department = department; }
public List<String> getSkills() { return skills; }
public void setSkills(List<String> skills) { this.skills = skills; }
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
", hireDate=" + hireDate +
", address=" + address +
", department=" + department +
", skills=" + skills +
'}';
}
}
测试类
public class PrototypeDeepCloneDemo {
public static void main(String[] args) throws CloneNotSupportedException {
System.out.println("========== 原型模式深克隆演示 ==========");
System.out.println();
// 创建原始对象
Employee original = createOriginalEmployee();
System.out.println("【原始对象】");
System.out.println(original);
System.out.println();
// 方式一:使用clone()方法进行深克隆
System.out.println("========== 方式一:通过clone()方法 ==========");
Employee cloned1 = original.clone();
// 验证是否深克隆(对象地址是否相同)
System.out.println("原始对象和克隆对象是否是同一个对象: " +
(original == cloned1));
System.out.println("原始对象和克隆对象的address是否相同: " +
(original.getAddress() == cloned1.getAddress()));
System.out.println("原始对象和克隆对象的department是否相同: " +
(original.getDepartment() == cloned1.getDepartment()));
System.out.println("原始对象和克隆对象的skills是否相同: " +
(original.getSkills() == cloned1.getSkills()));
System.out.println();
// 修改克隆对象的属性
System.out.println("【修改克隆对象1的地址】");
cloned1.modifyAddress("修改后的详细地址");
cloned1.addSkill("新增技能:Python");
System.out.println("原始对象: " + original);
System.out.println("克隆对象: " + cloned1);
System.out.println();
// 方式二:使用序列化进行深克隆
System.out.println("========== 方式二:通过序列化 ==========");
Employee cloned2 = original.deepCloneBySerialization();
System.out.println("原始对象和序列化克隆对象是否是同一个对象: " +
(original == cloned2));
System.out.println("原始对象和序列化克隆对象的address是否相同: " +
(original.getAddress() == cloned2.getAddress()));
// 修改克隆对象2的属性
cloned2.setName("修改后的姓名");
cloned2.getDepartment().setManager("新经理");
cloned2.addSkill("人工智能");
System.out.println("原始对象: " + original);
System.out.println("序列化克隆对象: " + cloned2);
System.out.println();
// 对比两种方式
System.out.println("========== 两种方式对比 ==========");
System.out.println("1. clone()方法:需要重写,手动处理所有引用字段");
System.out.println(" 优点:性能较高");
System.out.println(" 缺点:代码繁琐,需要手动管理所有引用类型");
System.out.println();
System.out.println("2. 序列化方式:通过序列化和反序列化实现");
System.out.println(" 优点:代码简单,自动处理所有引用字段");
System.out.println(" 缺点:性能较低,要求所有类必须实现Serializable");
}
private static Employee createOriginalEmployee() {
// 创建地址
Address address = new Address("广东", "深圳", "南山科技园");
// 创建部门
Department department = new Department("技术部", "张三");
// 创建技能列表
List<String> skills = new ArrayList<>();
skills.add("Java");
skills.add("Spring");
skills.add("MySQL");
// 创建员工对象
return new Employee(
"李四",
28,
15000.0,
new Date(),
address,
department,
skills
);
}
}
运行结果
========== 原型模式深克隆演示 ==========
【原始对象】
Employee{name='李四', age=28, salary=15000.0, hireDate=Mon Jun 24 10:30:00 CST 2024, address=广东省深圳市南山科技园, department=技术部(负责人:张三), skills=[Java, Spring, MySQL]}
========== 方式一:通过clone()方法 ==========
原始对象和克隆对象是否是同一个对象: false
原始对象和克隆对象的address是否相同: false
原始对象和克隆对象的department是否相同: false
原始对象和克隆对象的skills是否相同: false
【修改克隆对象1的地址】
原始对象: Employee{name='李四', age=28, salary=15000.0, hireDate=Mon Jun 24 10:30:00 CST 2024, address=广东省深圳市南山科技园, department=技术部(负责人:张三), skills=[Java, Spring, MySQL]}
克隆对象: Employee{name='李四', age=28, salary=15000.0, hireDate=Mon Jun 24 10:30:00 CST 2024, address=广东省深圳市修改后的详细地址, department=技术部(负责人:张三), skills=[Java, Spring, MySQL, Python]}
========== 方式二:通过序列化 ==========
原始对象和序列化克隆对象是否是同一个对象: false
原始对象和序列化克隆对象的address是否相同: false
【修改克隆对象2的属性】
原始对象: Employee{name='李四', age=28, salary=15000.0, hireDate=Mon Jun 24 10:30:00 CST 2024, address=广东省深圳市南山科技园, department=技术部(负责人:张三), skills=[Java, Spring, MySQL]}
序列化克隆对象: Employee{name='修改后的姓名', age=28, salary=15000.0, hireDate=Mon Jun 24 10:30:00 CST 2024, address=广东省深圳市南山科技园, department=技术部(负责人:新经理), skills=[Java, Spring, MySQL, 人工智能]}
关键点说明
深克隆核心思想
- 不仅要复制对象本身,还要复制对象引用的所有对象
- 确保克隆对象和原始对象互不影响
两种实现方式对比
| 特性 | clone()方法 | 序列化方式 |
|---|---|---|
| 代码复杂度 | 需要手动处理所有引用 | 代码简单 |
| 性能 | 较快 | 较慢 |
| 实现要求 | 实现Cloneable接口 | 实现Serializable接口 |
| 对象深度 | 需要控制克隆深度 | 自动处理所有层级 |
| final字段 | 无法处理 | 可以处理 |
适用场景
- 对象创建成本较高时
- 需要保留对象状态时
- 复杂对象的复制
注意事项
- 深克隆会完全断开所有引用关系
- 性能开销相对较大(特别是序列化方式)
- 要确保所有引用类型都正确处理
这个案例完整展示了深克隆的两种实现方式,并通过实际运行证明了深克隆后对象之间的完全独立性。