Skip to content

原型模式是"用克隆代替 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") 就是原型思想的落地

相关:《单例模式》(单例是"只有一个",原型是"每次克隆新对象",正好相反)。