#
Prototype
#
概念
用一个已经存在的对象作为原型,通过 复制(clone) 来创建新的对象,而不是通过 new。这样可以避免复杂对象的重复初始化,提高性能。
#
结构
原型模式一般包含两个角色:
- 抽象原型(Prototype):声明 clone() 方法。
- 具体原型(ConcretePrototype):实现 clone() 方法,可以返回自身的拷贝。
#
例子
Java 中 Object 类已经提供了 clone() 方法(浅拷贝),只要类实现 Cloneable 接口,就能用原型模式。 浅拷贝
class Resume implements Cloneable {
private String name;
private int age;
private String workExperience;
public Resume(String name, int age, String workExperience) {
this.name = name;
this.age = age;
this.workExperience = workExperience;
}
public void show() {
System.out.println(name + " | 年龄: " + age + " | 工作经验: " + workExperience);
}
@Override
protected Resume clone() {
try {
return (Resume) super.clone(); // 浅拷贝
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
public class PrototypeDemo {
public static void main(String[] args) {
Resume r1 = new Resume("张三", 25, "2年Java开发经验");
Resume r2 = r1.clone(); // 克隆一个副本
Resume r3 = r1.clone();
r1.show();
r2.show();
r3.show();
}
}
深拷贝
import java.util.ArrayList;
import java.util.List;
// 学生类
class Student implements Cloneable {
private String name;
private int age;
private List<String> courses; // 引用类型字段
public Student(String name, int age, List<String> courses) {
this.name = name;
this.age = age;
this.courses = courses;
}
public void addCourse(String course) {
this.courses.add(course);
}
public void showInfo() {
System.out.println("姓名: " + name + ", 年龄: " + age + ", 课程: " + courses);
}
// 深拷贝(手动复制)
@Override
protected Student clone() {
try {
// 先浅拷贝基本字段
Student copy = (Student) super.clone();
// 再手动拷贝引用类型字段
copy.courses = new ArrayList<>(this.courses);
return copy;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
// 测试
public class DeepCloneManualDemo {
public static void main(String[] args) {
List<String> courses = new ArrayList<>();
courses.add("Java");
courses.add("数据库");
Student s1 = new Student("李四", 21, courses);
// 深拷贝
Student s2 = s1.clone();
// 修改 s1 的课程
s1.addCourse("操作系统");
System.out.println("=== 原始对象 ===");
s1.showInfo();
System.out.println("=== 深拷贝对象 ===");
s2.showInfo();
}
}
深拷贝可以通过实现序列化接口的方式实现
import java.io.*;
import java.util.ArrayList;
import java.util.List;
// 学生类
class Student implements Cloneable, Serializable {
private String name;
private int age;
private List<String> courses; // 引用类型字段
public Student(String name, int age, List<String> courses) {
this.name = name;
this.age = age;
this.courses = courses;
}
public void addCourse(String course) {
this.courses.add(course);
}
public void showInfo() {
System.out.println("姓名: " + name + ", 年龄: " + age + ", 课程: " + courses);
}
// 浅拷贝
@Override
protected Student clone() {
try {
return (Student) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
// 深拷贝(通过序列化实现)
public Student deepClone() {
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 (Student) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
// 测试
public class DeepCloneDemo {
public static void main(String[] args) {
List<String> courses = new ArrayList<>();
courses.add("Java");
courses.add("数据库");
Student s1 = new Student("张三", 20, courses);
// 浅拷贝
Student s2 = s1.clone();
// 深拷贝
Student s3 = s1.deepClone();
// 修改 s1 的课程
s1.addCourse("操作系统");
System.out.println("=== 原始对象 ===");
s1.showInfo();
System.out.println("=== 浅拷贝对象 ===");
s2.showInfo();
System.out.println("=== 深拷贝对象 ===");
s3.showInfo();
}
}
#
浅拷贝
- 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
- 只复制对象本身和基本类型字段,如果对象里有引用类型字段(比如数组、集合),只会复制引用,指向同一块内存。
#
深拷贝
- 不仅复制对象本身,还会递归复制引用类型字段,生成完全独立的副本。
- 不仅复制对象本身,还会递归复制引用类型字段,生成完全独立的副本。
#
优点
- 快速复制对象,性能比 new 更高(尤其是复杂对象)。
- 隔离了对象创建过程,客户端不用知道创建细节。
#
缺点
- 必须实现 Cloneable 并重写 clone(),有一定侵入性。
- 深拷贝实现较复杂。
#
使用场景
- 需要频繁创建相似对象(比如游戏中的怪物、地图元素)。
- 初始化代价大(如配置类、数据库连接信息)。
- 需要保存对象状态,并在后续快速恢复。