原型模式是"用克隆代替 new"——复制一个已有对象,而不是从头创建。它在"创建对象成本高"或"对象结构复杂"时特别有用。这篇讲清原型怎么实现、以及 Java 里克隆的坑。
一、解决什么问题:创建成本高、结构复杂
new 一个对象通常很快,但有些对象创建成本高——比如要查数据库、读配置、初始化一堆字段。如果已经有一个"模板对象",直接复制它比重新创建快得多、简单得多。
原型模式就是:以已有对象为原型,克隆出新对象。
二、核心:克隆方法
java
// 原型接口:声明克隆方法
interface Prototype {
Prototype clone();
}
class Config implements Prototype {
private String dbUrl;
private String username;
// ... 一堆配置字段
@Override
public Config clone() {
Config c = new Config();
c.dbUrl = this.dbUrl;
c.username = this.username;
return c; // 复制出字段相同的新对象
}
}
// 使用:拿原型克隆,不用重新加载配置
Config template = loadConfig(); // 原型(加载一次)
Config c1 = template.clone(); // 克隆,省去重新加载
Config c2 = template.clone();三、Java 的浅拷贝 vs 深拷贝(坑)
Java 的 Object.clone() 是浅拷贝——引用类型字段只复制引用,不复制指向的对象:
java
class Order implements Cloneable {
private List<Item> items; // 引用类型字段
@Override
public Order clone() {
return (Order) super.clone(); // 浅拷贝:items 还是同一个 List!
}
}浅拷贝后,原对象和克隆对象的 items 指向同一个 List,改一个另一个也跟着变。要深拷贝,得手动克隆引用字段:
java
@Override
public Order clone() {
Order o = (Order) super.clone();
o.items = new ArrayList<>(this.items); // 深拷贝:复制 List 本身
return o;
}关键:原型模式要注意深浅拷贝——简单类型字段浅拷贝就够,引用类型字段要深拷贝,否则两个对象会"共享"同一份数据。
四、实际应用
- Spring 的
@Scope("prototype"):每次获取都返回一个新的 bean 实例(原型作用域) - 配置模板:加载一次配置模板,之后 clone 出多个副本
- 游戏/编辑器:复制对象(怪物、文档快照)
小结
- 原型 = 用克隆代替 new,适合"创建成本高"的对象
- Java
clone()默认浅拷贝,引用字段要手动深拷贝 - Spring
@Scope("prototype")就是原型思想的落地
相关:《单例模式》(单例是"只有一个",原型是"每次克隆新对象",正好相反)。
