原型模式(Prototype Pattern)是一种创建型模式,通过复制(克隆)一个已有对象来创建新对象,而不是通过 new 重新实例化。

核心思想

当创建一个对象的代价较大(如需要复杂初始化、数据库查询、网络请求等)时,可以先创建一个原型对象,后续通过克隆该原型来快速获得新对象。

角色

  • Prototype(抽象原型):声明克隆方法 clone()
  • ConcretePrototype(具体原型):实现克隆方法,返回自身的副本。
  • Client(客户端):通过调用原型的克隆方法来创建新对象。

浅克隆与深克隆

浅克隆(Shallow Clone) 深克隆(Deep Clone)
基本类型字段 复制值 复制值
引用类型字段 复制引用(共享对象) 递归复制,独立对象
修改互不影响 ❌ 引用字段会互相影响 ✅ 完全独立

示例:细胞克隆

Java 通过实现 Cloneable 接口来支持浅克隆:

public class Cell implements Cloneable {

    private String cellWall;       // 细胞壁
    private String cellMembrane;   // 细胞膜
    private String cellularTissue; // 细胞组织

    public String getCellWall() { return cellWall; }
    public void setCellWall(String cellWall) { this.cellWall = cellWall; }

    // 其他 getter/setter 省略

    @Override
    public Cell clone() {
        try {
            return (Cell) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new InternalError(e.getMessage());
        }
    }
}

客户端使用:

public class Client {

    public static void main(String[] args) {
        // 创建原型细胞
        Cell cell = new Cell();
        cell.setCellWall("cell wall 1");

        // 克隆原型细胞
        Cell clonedCell = cell.clone();

        System.out.println(cell == clonedCell);                    // false,是不同对象
        System.out.println(cell.getCellWall().equals(clonedCell.getCellWall())); // true,值相同
    }
}

深克隆示例

当对象包含引用类型字段时,需要手动实现深克隆:

public class DeepCell implements Cloneable {

    private String name;
    private List<String> components; // 引用类型

    @Override
    public DeepCell clone() {
        try {
            DeepCell copy = (DeepCell) super.clone();
            // 手动深克隆引用类型字段
            copy.components = new ArrayList<>(this.components);
            return copy;
        } catch (CloneNotSupportedException e) {
            throw new InternalError(e.getMessage());
        }
    }
}

优点

  • 性能好:避免重复执行昂贵的初始化操作,直接克隆已有对象。
  • 简化对象创建:客户端无需知道具体类,只需调用 clone()
  • 动态增减产品:运行时可以注册和取消注册原型对象。

缺点

  • 深克隆实现复杂:当对象结构嵌套较深时,深克隆的实现较为繁琐。
  • 必须实现克隆接口:每个需要克隆的类都要实现 Cloneable,侵入性较强。

适用场景

  • 创建对象的成本很高(如从数据库加载、复杂计算)
  • 需要创建大量相似对象
  • 希望避免与具体类耦合,通过克隆动态获取对象
  • 典型场景:游戏中的敌人生成、文档模板复制、配置对象复制