【设计模式】【创建型模式】原型模式(Prototype)

简介: 一、入门 什么是原型模式? 原型模式(Prototype Pattern)是一种创建型设计模式,它通过复制现有对象来创建新对象,而不是通过实例化类。 原型模式的核心是克隆(Clone),即通过复制现有

👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD

🔥 2025本人正在沉淀中... 博客更新速度++

👍 欢迎点赞、收藏、关注,跟上我的更新节奏

🎵 当你的天空突然下了大雨,那是我在为你炸乌云

一、入门

什么是原型模式?

原型模式(Prototype Pattern)是一种创建型设计模式,它通过复制现有对象来创建新对象,而不是通过实例化类。
原型模式的核心是克隆(Clone),即通过复制现有对象来创建新对象。Java 提供了 Cloneable 接口和 clone() 方法来实现对象的浅拷贝。

为什么要有原型模式?

  1. 对象创建成本高
    • 问题:某些对象的创建过程可能非常复杂,涉及大量的计算或资源消耗。例如,数据库连接、网络请求、复杂的初始化过程等。
    • 解决方案:通过原型模式,可以直接复制现有对象,避免重复进行高成本的初始化过程。
  2. 需要动态配置对象
    • 问题:在某些情况下,对象的配置需要在运行时动态确定,而不是在编译时确定。如果每次都需要重新创建和配置对象,会导致代码复杂且难以维护。
    • 解决方案:原型模式允许通过复制现有对象来创建新对象,并根据需要动态修改其配置。
  3. 避免子类化
    • 问题:在某些情况下,通过继承来扩展对象的功能会导致类层次结构复杂,难以维护。
    • 解决方案:原型模式通过复制现有对象来创建新对象,而不是通过继承来扩展功能,从而简化了类层次结构。
  4. 保持对象状态
    • 问题:在某些情况下,需要创建与现有对象状态相同的新对象。如果每次都手动复制对象的状态,会导致代码冗余且容易出错。
    • 解决方案:原型模式通过克隆现有对象来自动复制其状态,减少了手动复制状态的工作量。

如何实现原型模式?

原型模式由以下角色组成:

  1. 原型接口(Prototype Interface)
    • 定义克隆方法的接口或抽象类。
    • 在 Java 中,通常使用 Cloneable 接口来标记类支持克隆。
  2. 具体原型类(Concrete Prototype)
    • 实现原型接口的具体类,负责实现克隆方法。
    • 通常需要重写 clone() 方法来定义具体的克隆逻辑。
  3. 客户端(Client)
    • 使用原型对象的类,通过调用原型对象的克隆方法来创建新对象。

【案例】打印身份证

image.png

假设你需要复印身份证,每次复印时,原始身份证的内容(姓名、身份证号、地址等)是固定的,但复印件的用途可能不同(如用于银行开户、办理签证等)。如果每次都重新填写身份证信息,效率很低。
原型模式解决方案:

  1. 身份证原件(原型):包含固定的个人信息。
  2. 复印件(克隆对象):复制原件的内容,并根据用途添加额外信息(如用途备注)。

原型接口(Cloneable 是 Java 内置接口): Prototype接口

interface Prototype extends Cloneable {
   
    Prototype clone();
}

具体原型类(Concrete Prototype) IDCard

class IDCard implements Prototype {
   
    private String name;
    private String idNumber;
    private String address;
    private String purpose; // 复印件的用途

    public IDCard(String name, String idNumber, String address) {
   
        this.name = name;
        this.idNumber = idNumber;
        this.address = address;
    }

    public void setPurpose(String purpose) {
   
        this.purpose = purpose;
    }

    @Override
    public IDCard clone() {
   
        try {
   
            return (IDCard) super.clone(); // 调用 Object 的 clone() 方法
        } catch (CloneNotSupportedException e) {
   
            throw new RuntimeException(e);
        }
    }

    @Override
    public String toString() {
   
        return "IDCard{" +
                "name='" + name + '\'' +
                ", idNumber='" + idNumber + '\'' +
                ", address='" + address + '\'' +
                ", purpose='" + purpose + '\'' +
                '}';
    }
}

客户端

class CopyMachine {
   
    public static void main(String[] args) {
   
        // 创建身份证原件
        IDCard originalIDCard = new IDCard("张三", "123456789012345678", "北京市朝阳区");

        // 复印身份证用于银行开户
        IDCard copyForBank = originalIDCard.clone();
        copyForBank.setPurpose("银行开户");

        // 复印身份证用于办理签证
        IDCard copyForVisa = originalIDCard.clone();
        copyForVisa.setPurpose("办理签证");

        // 打印结果
        System.out.println("原件: " + originalIDCard);
        System.out.println("银行开户复印件: " + copyForBank);
        System.out.println("办理签证复印件: " + copyForVisa);
    }
}

二、原型模式在框架源码中的使用

JDK 的 Object.clone()

Java 的根类 Object 提供了 clone() 方法,它是原型模式的底层实现基础。任何实现 Cloneable 接口的类都可以通过 clone() 方法创建新对象。

public class Object {
   
    protected native Object clone() throws CloneNotSupportedException;
}

使用约束

  • 必须实现 Cloneable 接口:否则调用 clone() 会抛出 CloneNotSupportedException
  • 默认是浅拷贝:需要深拷贝时,必须手动重写 clone() 方法。

Java 集合框架中的 ArrayList.clone()

Java 的 ArrayList 类实现了 Cloneable 接口,其 clone() 方法通过浅拷贝快速复制一个新的列表。

ArrayList<String> original = new ArrayList<>();
original.add("A");
original.add("B");

ArrayList<String> copy = (ArrayList<String>) original.clone();
copy.add("C");

System.out.println(original); // 输出 [A, B]
System.out.println(copy);     // 输出 [A, B, C]
源码实现
public class ArrayList<E> implements Cloneable {
   
    // ...

    public Object clone() {
   
        try {
   
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
   
            throw new InternalError(e);
        }
    }
}

Spring Framework 中的 Prototype Bean

Spring 框架中的 Bean 作用域(Scope)之一是 prototype,它表示每次从容器中获取 Bean 时都会创建一个新的实例。这本质上是原型模式的一种应用。

<!-- XML 配置 -->
<bean id="prototypeBean" class="com.example.PrototypeBean" scope="prototype"/>
// Java 代码中获取 Bean
ApplicationContext context = ...;
PrototypeBean bean1 = context.getBean(PrototypeBean.class);
PrototypeBean bean2 = context.getBean(PrototypeBean.class);

// bean1 和 bean2 是两个不同的实例
System.out.println(bean1 == bean2); // 输出 false

设计思想

  • 核心机制:Spring 容器内部维护一个原型 Bean 的模板,每次调用 getBean() 时,基于模板创建一个新对象(通过反射或 CGLIB 动态代理)。
  • 优势:避免单例 Bean 的线程安全问题,适用于需要独立状态的场景(如 HTTP 请求处理)。

三、总结

原型模式的优点

  1. 高效创建对象
    • 通过复制现有对象来创建新对象,避免了重复的初始化过程,特别适用于创建成本较高的对象(如数据库连接、复杂计算对象)。
    • 例如,Spring 的 Prototype Bean 每次请求都会创建一个新实例,避免了单例 Bean 的线程安全问题。
  2. 动态配置对象
    • 可以在运行时动态修改克隆对象的属性,而不需要重新初始化。
    • 例如,复制一个配置对象后,可以根据需要调整某些参数。
  3. 减少子类化
    • 通过复制现有对象来创建新对象,而不是通过继承来扩展功能,避免了类层次结构的复杂性。
    • 例如,JavaScript 中的原型继承就是通过复制原型对象来实现的。
  4. 标准化对象创建
    • 提供统一的克隆接口(如 Cloneable),使得对象创建过程更加标准化和可控。

原型模式的缺点

  1. 深拷贝与浅拷贝问题
    • 默认的 clone() 方法是浅拷贝,如果对象包含引用类型字段,克隆对象和原对象会共享这些字段,可能导致意外的副作用。
    • 实现深拷贝需要额外的工作(如手动复制引用类型字段或使用序列化工具)。
  2. 实现复杂度
    • 如果对象结构非常复杂(如包含嵌套对象、循环引用等),实现深拷贝可能会变得复杂且容易出错。
  3. 破坏封装性
    • clone() 方法是 Object 类的受保护方法,需要在子类中重写并公开,这可能破坏类的封装性。
  4. 性能问题
    • 深拷贝(如基于序列化的拷贝)可能比较耗时,特别是在对象结构复杂或数据量大的情况下。

原型模式的适用场景

  1. 对象创建成本高
    • 当对象的创建过程涉及复杂的计算、资源消耗(如数据库连接、网络请求)或耗时操作时,使用原型模式可以显著提高性能。
    • 例如,Spring 的 Prototype Bean 适用于需要独立状态的场景。
  2. 需要动态配置对象
    • 当对象的配置需要在运行时动态确定时,可以通过克隆现有对象并修改其属性来实现。
    • 例如,复制一个配置模板并根据环境调整参数。
  3. 避免子类化
    • 当需要通过扩展对象的功能来创建新对象,但又不想引入复杂的类层次结构时,可以使用原型模式。
    • 例如,JavaScript 中的原型继承。
  4. 需要保持对象状态一致性
    • 当需要创建与现有对象状态相同的新对象时,可以通过克隆来确保状态一致性。
    • 例如,游戏中的敌人生成、缓存对象的复制。
  5. 框架中的对象管理
    • 在框架中,原型模式常用于管理对象的生命周期和创建过程(如 Spring 的 Prototype Bean、Java 集合框架的 clone() 方法)。
目录
相关文章
|
1月前
|
设计模式 Java 数据库连接
【设计模式】【创建型模式】工厂方法模式(Factory Methods)
一、入门 什么是工厂方法模式? 工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个用于创建对象的接口,但由子类决定实例化哪个类。工厂方法模式使类的实例化延迟
79 16
|
1月前
|
设计模式 缓存 安全
【设计模式】【创建型模式】单例模式(Singleton)
一、入门 什么是单例模式? 单例模式是一种设计模式,确保一个类只有一个实例,并提供一个全局访问点。它常用于需要全局唯一对象的场景,如配置管理、连接池等。 为什么要单例模式? 节省资源 场景:某些对象创
100 15
|
1月前
|
设计模式 Java Apache
【设计模式】【创建型模式】建造者模式(Builder)
一、入门 什么是建造者模式? 建造者模式(Builder Pattern)是一种创建型设计模式,用于逐步构建复杂对象。 它通过将对象的构建过程与表示分离,使得相同的构建过程可以创建不同的表示。 为什么
104 14
|
1月前
|
设计模式 Java 关系型数据库
【设计模式】【创建型模式】抽象工厂模式(Abstract Factory)
一、入门 什么是抽象工厂模式? 抽象工厂模式是一种创建型设计模式,它提供了一个接口,用于创建相关或依赖对象的家族,而不需要指定具体的类。 简单来说,抽象工厂模式是工厂方法模式的升级版,它能够创建一组相
102 14
|
3月前
|
设计模式 XML Java
设计模式觉醒系列(03)创建型模式的5个设计模式 | 一口气讲全讲透
本文详细介绍了设计模式中的创建型模式,包括建造者模式、原型模式、单例模式、工厂方法模式和抽象工厂模式。创建型模式关注对象的创建过程,隐藏了创建细节,以提高代码的可维护性和可扩展性。通过具体的实战demo和应用场景分析,展示了每种模式的特点和优势。例如,建造者模式适用于复杂对象的分步骤构建;原型模式通过复制对象实现高效复用;单例模式确保全局唯一实例;工厂方法模式和抽象工厂模式则提供了灵活的对象创建机制,支持多类型产品族的生产。这些模式在实际开发中能够简化客户端代码,提升系统灵活性和复用性。
|
5月前
|
设计模式 存储 Java
「全网最细 + 实战源码案例」设计模式——原型模式
原型模式(Prototype Pattern)是一种创建型设计模式,通过复制现有对象来创建新对象,适用于创建成本高或复杂的对象场景。其核心思想是“克隆”,避免直接实例化类。结构上分为抽象原型类、具体原型类和客户端。优点包括减少对象创建成本、隐藏复杂性、简化实例创建;缺点是处理循环引用的复杂对象时较为麻烦。实现步骤为定义原型类、重写`clone()`方法并调用。注意事项包括浅拷贝与深拷贝的区别及`Cloneable`接口的使用。
103 20
|
6月前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
6月前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
7月前
|
设计模式 架构师 Java
设计模式之 5 大创建型模式,万字长文深剖 ,近 30 张图解!
设计模式是写出优秀程序的保障,是让面向对象保持结构良好的秘诀,与架构能力与阅读源码的能力息息相关,本文深剖设计模式之 5 大创建型模式。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
设计模式之 5 大创建型模式,万字长文深剖 ,近 30 张图解!
|
9月前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑】设计模式——原型模式
对比原型模式和传统方式的实现思路、代码方案、优缺点,阐述原型模式的使用场景,以及深拷贝、浅拷贝等相关概念,并扩展原型模式在Spring源码中的应用。
【Java笔记+踩坑】设计模式——原型模式