目录

原型模式 (Prototype Pattern)

通过复制现有对象来创建新对象,避免重复的初始化操作

概述

原型模式是一种创建型设计模式,它允许通过复制现有对象来创建新对象,而不是从头开始创建。

适用场景

  • 对象创建成本高(需要复杂计算或数据库操作)
  • 需要创建与现有对象相似的对象
  • 运行时动态决定创建哪种对象

基础实现

实现 Cloneable 接口

// 原型接口
public interface Prototype extends Cloneable {
    Prototype clone();
}

// 具体原型类
public class Document implements Cloneable {
    private String title;
    private String content;
    private List<String> tags;
    
    public Document(String title, String content, List<String> tags) {
        this.title = title;
        this.content = content;
        this.tags = tags;
    }
    
    // 浅拷贝
    @Override
    public Document clone() {
        try {
            return (Document) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }
    
    // Getters and Setters...
}

// 使用
Document template = new Document("模板", "内容", Arrays.asList("标签1"));
Document doc1 = template.clone();
doc1.setTitle("文档1");

深拷贝 vs 浅拷贝

浅拷贝问题

// 浅拷贝:引用类型共享
Document doc1 = template.clone();
doc1.getTags().add("新标签");
// template  tags 也会被修改

深拷贝实现

public class Document implements Cloneable, Serializable {
    private String title;
    private String content;
    private List<String> tags;
    private Author author;
    
    // 深拷贝方式 1:手动复制
    @Override
    public Document clone() {
        try {
            Document cloned = (Document) super.clone();
            // 复制引用类型
            cloned.tags = new ArrayList<>(this.tags);
            cloned.author = this.author.clone();
            return cloned;
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }
    
    // 深拷贝方式 2:序列化
    public Document deepClone() {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(this);
            oos.close();
            
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            Document cloned = (Document) ois.readObject();
            ois.close();
            
            return cloned;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

// Author 类也需要实现 Cloneable
public class Author implements Cloneable, Serializable {
    private String name;
    private String email;
    
    @Override
    public Author clone() {
        try {
            return (Author) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }
}

使用拷贝构造函数

public class Document {
    private String title;
    private String content;
    private List<String> tags;
    
    // 普通构造
    public Document(String title, String content, List<String> tags) {
        this.title = title;
        this.content = content;
        this.tags = new ArrayList<>(tags);
    }
    
    // 拷贝构造(深拷贝)
    public Document(Document other) {
        this.title = other.title;
        this.content = other.content;
        this.tags = new ArrayList<>(other.tags);
    }
}

// 使用
Document doc1 = new Document("原文档", "内容", tags);
Document doc2 = new Document(doc1); // 深拷贝
doc2.setTitle("新文档");

原型注册表

// 原型管理器
public class PrototypeRegistry {
    private static final Map<String, Prototype> prototypes = new HashMap<>();
    
    static {
        // 注册默认原型
        prototypes.put("default", new Report("默认报告", "模板内容"));
        prototypes.put("monthly", new Report("月度报告", "月度数据..."));
        prototypes.put("annual", new Report("年度报告", "年度总结..."));
    }
    
    public static void register(String key, Prototype prototype) {
        prototypes.put(key, prototype);
    }
    
    public static Prototype create(String key) {
        Prototype prototype = prototypes.get(key);
        if (prototype == null) {
            throw new IllegalArgumentException("未知原型: " + key);
        }
        return prototype.clone();
    }
}

// 使用
Report report = (Report) PrototypeRegistry.create("monthly");
report.setTitle("2024年1月月报");

框架中的应用

Spring 原型作用域

@Component
@Scope("prototype")
public class PrototypeBean {
    private String data;
    
    public void setData(String data) {
        this.data = data;
    }
}

// 使用
@Configuration
public class AppConfig {
    @Autowired
    private ApplicationContext context;
    
    public void usePrototype() {
        // 每次获取都是新实例
        PrototypeBean bean1 = context.getBean(PrototypeBean.class);
        PrototypeBean bean2 = context.getBean(PrototypeBean.class);
        
        System.out.println(bean1 == bean2); // false
    }
}

JSON 对象的复制

import com.fasterxml.jackson.databind.ObjectMapper;

public class DeepCopyUtil {
    private static final ObjectMapper mapper = new ObjectMapper();
    
    public static <T> T copy(T object, Class<T> clazz) {
        try {
            String json = mapper.writeValueAsString(object);
            return mapper.readValue(json, clazz);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

// 使用
User user1 = new User("john", 25);
User user2 = DeepCopyUtil.copy(user1, User.class);

实际应用:报表生成

public abstract class ReportTemplate implements Cloneable {
    protected String title;
    protected String header;
    protected String footer;
    protected List<String> sections;
    
    public ReportTemplate(String title) {
        this.title = title;
        this.sections = new ArrayList<>();
    }
    
    // 添加内容
    public void addSection(String section) {
        sections.add(section);
    }
    
    // 生成报告
    public String generate() {
        StringBuilder report = new StringBuilder();
        report.append(header).append("\n");
        report.append("标题: ").append(title).append("\n");
        for (String section : sections) {
            report.append(section).append("\n");
        }
        report.append(footer);
        return report.toString();
    }
    
    @Override
    public ReportTemplate clone() {
        try {
            ReportTemplate cloned = (ReportTemplate) super.clone();
            cloned.sections = new ArrayList<>(this.sections);
            return cloned;
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }
}

// 月度报告
public class MonthlyReport extends ReportTemplate {
    public MonthlyReport() {
        super("月度报告");
        this.header = "===== 月度报告 =====";
        this.footer = "===== 报告结束 =====";
    }
}

// 使用
MonthlyReport template = new MonthlyReport();
template.addSection("销售额: 100万");
template.addSection("用户数: 5000");

// 克隆并定制
MonthlyReport janReport = template.clone();
janReport.addSection("月份: 1月");

MonthlyReport febReport = template.clone();
febReport.addSection("月份: 2月");

深拷贝方式对比

方式优点缺点
clone()标准方法需要实现 Cloneable
序列化自动深拷贝性能较差
拷贝构造简单直观需要手动复制每个字段
JSON 复制通用性强依赖库,性能一般
BeanUtils方便性能较差,部分字段可能无法复制

优缺点

优点缺点
避免子类化复杂对象的深拷贝实现困难
动态添加/删除产品需要实现克隆方法
减少初始化代码深拷贝可能有循环引用问题

最佳实践

  1. 优先使用拷贝构造:比 clone() 更清晰
  2. 注意深拷贝问题:特别是集合和对象引用
  3. 不可变对象:可以安全使用浅拷贝
  4. 原型注册表:管理常用原型对象