目录
序幕:当复制对象成为战略需求
🎮 游戏开发现场:
你需要快速生成1000个外形相同但位置不同的敌人,直接new对象导致内存飙升?文档编辑器需要支持"无限撤销"功能,如何保存编辑状态的每一帧?这些场景都需要深谙"复制之道"的原型模式来破局!
一、原型工厂的核心装备库
1.1 Java原生的浅克隆术
// 基础忍者原型
public class Ninja implements Cloneable {
private String name;
private Weapon weapon; // 引用对象共享
public Ninja(String name, Weapon weapon) {
this.name = name;
this.weapon = weapon;
}
@Override
public Ninja clone() {
try {
return (Ninja) super.clone(); // 浅克隆
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
// 测试影分身效果
Ninji naruto = new Ninja("鸣人", new Kunai());
Ninja shadowClone = naruto.clone();
System.out.println(naruto == shadowClone); // false
System.out.println(naruto.weapon == shadowClone.weapon); // true ❗
浅克隆缺陷警告:
- 引用类型共享导致意外修改
- 嵌套对象无法实现真正隔离
- 需要人工递归克隆对象树
二、深度克隆的炼金法则
2.1 手工克隆大法(硬核派)
// 深克隆示例
public class DeepNinja implements Cloneable {
private String name;
private Weapon weapon;
@Override
public DeepNinja clone() {
DeepNinja clone = (DeepNinja) super.clone();
clone.weapon = this.weapon.clone(); // 武器也要克隆
return clone;
}
}
// 武器类的克隆支持
public class Weapon implements Cloneable {
private String type;
@Override
public Weapon clone() {
try {
return (Weapon) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
2.2 序列化克隆术(魔法派)
// 基于序列化的深克隆工具
public class CloneUtils {
@SuppressWarnings("unchecked")
public static <T extends Serializable> T deepClone(T obj) {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(obj);
try (ByteArrayInputStream bis =
new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis)) {
return (T) ois.readObject();
}
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException("克隆失败", e);
}
}
}
// 测试魔法克隆
Ninja sasuke = new Ninja("佐助", new Sword());
Ninja cloneArmy = CloneUtils.deepClone(sasuke);
三、原型模式的工业级装配
3.1 原型注册管理局
// 原型管理器
public class PrototypeRegistry {
private static Map<String, Ninja> prototypes = new HashMap<>();
static {
prototypes.put("naruto", new Ninja("鸣人", new Rasengan()));
prototypes.put("sakura", new Ninja("小樱", new MedicalSeal()));
}
public static Ninja getClone(String key) {
return prototypes.get(key).clone();
}
public static void addPrototype(String key, Ninja ninja) {
prototypes.put(key, ninja);
}
}
// 快速生成克隆军团
Ninja army1 = PrototypeRegistry.getClone("naruto");
Ninja army2 = PrototypeRegistry.getClone("sakura");
3.2 Spring框架中的原型容器
// 原型Bean定义
@Component
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ReportPrototype {
private byte[] content;
public void loadData(File file) {
// 加载大文件到内存...
}
}
// 使用时获取新实例
public class ReportService {
@Autowired
private ApplicationContext context;
public void generateReport() {
ReportPrototype report = context.getBean(ReportPrototype.class);
report.loadData(new File("data.xlsx"));
// 使用完自动回收...
}
}
四、原型模式的性能实验室
4.1 克隆 vs New性能对决
// 测试代码框架
long start = System.nanoTime();
for (int i = 0; i < 10000; i++) {
// 方案A: new Ninja(...)
// 方案B: prototype.clone()
}
long duration = System.nanoTime() - start;
测试结果对比(复杂对象创建场景):
操作方式 | 耗时(纳秒) | 内存占用(MB) |
---|---|---|
new | 352,000 | 145 |
clone | 78,000 | 62 |
结论:
- 对象构造越复杂,克隆优势越明显
- 简单对象反而可能new更快
五、原型模式三十六计
5.1 浅克隆适用场景
- 需要轻量级对象复制
- 确定所有引用都是不可变对象
- 需要与原型共享某些状态
5.2 深克隆必备场景
- 原型包含可变引用对象
- 需要完全隔离副本与原型
- 原型中存在集合或嵌套结构
5.3 模式选择决策树
终章:复制之术的哲学思考
设计启示:
- 克隆不是银弹,要评估对象复杂度
- 深克隆可能引发"递归地狱"陷阱
- 原型注册表可以成为系统单点故障
性能警钟:
// 错误!每次深克隆大文件对象
public class ReportService {
private Report hugeReport; // 100MB的报表对象
public Report createReport() {
return CloneUtils.deepClone(hugeReport); // 灾难性性能!
}
}
专家挑战:
当你的原型对象包含网络连接(Socket)这类不可序列化的资源时,如何实现安全的深克隆?把你的解决方案写在评论区!