【设计模式】原型模式(Prototype Pattern)详解

文章目录

    • [1. 引言:为什么不直接 new?](#1. 引言:为什么不直接 new?)
    • [2. 什么是原型模式](#2. 什么是原型模式)
      • [GoF 定义](#GoF 定义)
    • [3. 原型模式的核心思想](#3. 原型模式的核心思想)
    • [4. 原型模式的角色组成](#4. 原型模式的角色组成)
    • [5. Java 中的原型模式基础:Cloneable](#5. Java 中的原型模式基础:Cloneable)
    • [6. 示例场景:文档模板复制](#6. 示例场景:文档模板复制)
    • [7. 客户端使用](#7. 客户端使用)
    • [8. 浅拷贝 vs 深拷贝(重点)](#8. 浅拷贝 vs 深拷贝(重点))
      • [8.1 浅拷贝(Shallow Copy)](#8.1 浅拷贝(Shallow Copy))
      • [8.2 深拷贝(Deep Copy)](#8.2 深拷贝(Deep Copy))
      • [8.3 深拷贝的常见方式](#8.3 深拷贝的常见方式)
    • [9. 原型模式的优点](#9. 原型模式的优点)
    • [10. 原型模式的缺点](#10. 原型模式的缺点)
    • [11. 适用场景](#11. 适用场景)
    • [12. 原型模式在实际项目中的应用](#12. 原型模式在实际项目中的应用)
    • [13. 原型模式的一个重要提醒](#13. 原型模式的一个重要提醒)
    • 参考

1. 引言:为什么不直接 new?

在日常开发中,我们创建对象通常是这样的:

java 复制代码
MyObject obj = new MyObject();

但在某些场景下,创建一个对象并不"简单":

  • 对象初始化过程复杂
  • 需要访问数据库、配置文件或远程服务
  • 创建成本高、耗时长
  • 对象状态相似,仅少量字段不同

如果每次都通过 new 完整构建对象,会带来明显的性能开销。

这时,一个问题出现了:

能不能通过"复制"已有对象来创建新对象?

答案就是------原型模式(Prototype Pattern)。

原型模式解决的核心问题是:

如何在创建成本高的前提下,高效地生成相似对象。


2. 什么是原型模式

GoF 定义

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

一句话理解:

通过 clone 一个已有对象,来生成新对象,而不是重新 new。


3. 原型模式的核心思想

原型模式的核心是两个字:

拷贝

与工厂模式"关注如何创建对象"不同,原型模式关注的是:

  • 如何高效地复制对象
  • 如何避免复杂初始化过程

4. 原型模式的角色组成

原型模式通常包含三个角色:

  • 抽象原型类(Prototype):规定了具体原型对象必须实现的的 clone() 方法。
  • 具体原型类(ConcretePrototype):实现抽象原型类的 clone() 方法,它是可被复制的对象。
  • 访问类(Client):使用具体原型类中的 clone() 方法来复制新的对象。

结构非常简单:


5. Java 中的原型模式基础:Cloneable

Java 对原型模式提供了语言级支持:

  • Cloneable 接口

在Cloneable 接口中并没有声明任何方法。它只是被用来标记可以使用clone方法进行复制的。这样的接口被称为标记接口(marker interface),如下图。

  • Object.clone() 方法

使用方法:

  1. super:调用父类(Object 类)的 clone() 方法
  2. clone():Object 类中定义的本地(native)方法
  3. 整体意思是:"调用 Object 父类的 clone 方法进行浅拷贝"

6. 示例场景:文档模板复制

假设我们有一个文档对象,初始化过程非常复杂:

java 复制代码
public class Document implements Cloneable {

    private String title;
    private String content;

    public Document(String title, String content) {
        // 模拟复杂初始化
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ignored) {}
        this.title = title;
        this.content = content;
    }

    @Override
    protected Document clone() {
        try {
            return (Document) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}

注意:

  • Cloneable 是标记接口,没有任何方法
  • clone() 方法定义在 Object 类中,是 protected 方法
  • super 永远指向父类,接口不是父类

7. 客户端使用

java 复制代码
public class Client {
    public static void main(String[] args) {
        Document prototype = new Document("模板", "初始内容");

        Document copy1 = prototype.clone();
        Document copy2 = prototype.clone();
    }
}

效果:

  • 原型只初始化一次
  • 后续对象通过复制生成
  • 性能显著提升

8. 浅拷贝 vs 深拷贝(重点)

这是原型模式中最容易出问题的地方。


8.1 浅拷贝(Shallow Copy)

只复制对象本身,引用类型字段仍指向同一对象。

java 复制代码
public class Prototype implements Cloneable {
    private List<String> list;

    @Override
    protected Prototype clone() throws CloneNotSupportedException {
        return (Prototype) super.clone();
    }
}

问题:

  • 修改一个对象的 list
  • 所有 clone 出来的对象都会受影响

8.2 深拷贝(Deep Copy)

不仅复制对象本身,还复制其内部引用对象。

java 复制代码
@Override
protected Prototype clone() throws CloneNotSupportedException {
    Prototype copy = (Prototype) super.clone();
    copy.list = new ArrayList<>(this.list);
    return copy;
}

8.3 深拷贝的常见方式

  1. 手动 clone(最安全)
  2. 序列化 / 反序列化
  3. JSON 转换(不推荐用于高性能场景)

9. 原型模式的优点

  1. 提高性能
  2. 避免复杂初始化
  3. 动态创建对象
  4. 简化工厂类结构

10. 原型模式的缺点

  1. clone 实现复杂
  2. 深拷贝容易出错
  3. 破坏封装性
  4. 对象结构复杂时维护成本高

11. 适用场景

适合使用

  • 创建对象成本高
  • 对象差异小
  • 需要大量相似对象
  • 原型实例较稳定

不适合使用

  • 对象结构频繁变化
  • 包含大量不可变/不可复制资源
  • 业务复杂,维护成本高

12. 原型模式在实际项目中的应用

  • Spring 中的 scope="prototype"
  • 游戏开发中的角色/子弹复制
  • 文档、配置模板
  • UI 组件快速生成

当 new 一个对象太慢时,就考虑原型模式。


13. 原型模式的一个重要提醒

原型模式不是为了"少写代码",而是为了"少做重复初始化"。

如果对象创建本身就很轻量,没必要使用原型模式。


参考

原型模式 | 菜鸟教程

原型设计模式

原型模式-百度百科

《图解设计模式》

原型 - Java教程 - 廖雪峰的官方网站

相关推荐
长按助力退休5 小时前
设计模式实战,这 5 个最常用
设计模式
Carl_奕然7 小时前
【智能体】Agent的四种设计模式之:Multi-Agent Collaboration
设计模式
Lost of 程序猿7 小时前
建造者模式实战:告别“十参数构造函数“的数据导出任务
后端·设计模式·c#·asp.net
SL_staff7 小时前
合规性折旧:当知识资产因主权缺位在审计中‘功能性清零’
java·设计模式·开源
Zane199412 小时前
工厂方法一定比简单工厂高级?三种工厂模式到底该怎么选
设计模式
Hespethorn12 小时前
设计模式是语言缺陷的补丁 —— 从工厂、单例、策略三个模式说起
设计模式
Lost of 程序猿12 小时前
命令模式实战:把“下单后的动作“打包成可执行的任务
后端·设计模式·c#·asp.net·命令模式
一只旭宝12 小时前
【C++复习】四种类型转换 + 常见设计模式 + Redis/MySQL(后端面试复习完整版)
c++·redis·笔记·mysql·设计模式
YYYing.14 小时前
【设计模式系列 (四) 】建造者模式
c++·后端·设计模式·建造者模式·c/c++
Zane19941 天前
同一段单例代码,为什么在高并发下偶尔会创建出两个实例?聊聊哪种单例实现才是真的安全
设计模式