【从零入门23种设计模式04】创建型之原型模式

祝大家除夕快乐新年发大财!!!

一、原型模式的核心定义

原型模式是一种创建型设计模式 ,核心思想是:基于一个已存在的 "原型对象",通过 "克隆(复制)" 的方式创建新对象,而非通过 new 关键字从头初始化。可以类比成 "复印文件":已有一份写好的文件(原型),想要多份相同的文件时,直接复印(克隆)比重新手写(new + 初始化)效率高得多。

二、核心适用场景

当满足以下条件时,优先考虑原型模式:

  1. 对象创建成本高(比如初始化需要大量 IO 操作、数据库查询、网络请求);
  2. 需要频繁创建结构 / 属性相似的对象;
  3. 希望隐藏对象创建的复杂细节,只关注 "复制已有对象";
  4. 避免构造函数的复杂逻辑(比如构造函数参数过多、逻辑嵌套)。

三、实现方式(以 Java 为例)

Java 中实现原型模式的核心是:

  • 实现 Cloneable 接口(标记接口,仅表明该类支持克隆,无任何方法);
  • 重写 Object 类的 clone() 方法(Object 类的 clone() 是 protected,需重写为 public)。

原型模式分为两种核心克隆方式:浅克隆深克隆(新手最容易踩坑的点)。

1. 浅克隆(Shallow Clone)
定义

只克隆对象的 "基本数据类型成员变量",对于 "引用类型成员变量",仅克隆引用地址(新对象和原型对象共享同一个引用对象)。

代码示例
复制代码
// 原型类(实现Cloneable接口)
class User implements Cloneable {
    // 基本数据类型
    private int id;
    // 引用数据类型(自定义对象)
    private Address address;

    // 构造函数
    public User(int id, Address address) {
        this.id = id;
        this.address = address;
    }

    // 重写clone方法(浅克隆)
    @Override
    public User clone() {
        try {
            // 调用Object的clone()方法,实现浅克隆
            return (User) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError(); // 不会触发,因为实现了Cloneable
        }
    }

    // getter/setter(简化展示)
    public int getId() { return id; }
    public Address getAddress() { return address; }
    public void setId(int id) { this.id = id; }
}

// 引用类型成员类
class Address {
    private String city;

    public Address(String city) {
        this.city = city;
    }

    public String getCity() { return city; }
    public void setCity(String city) { this.city = city; }
}

// 测试浅克隆
public class PrototypeTest {
    public static void main(String[] args) {
        // 1. 创建原型对象
        Address addr = new Address("北京");
        User prototype = new User(1, addr);

        // 2. 克隆新对象
        User cloneUser = prototype.clone();

        // 3. 验证结果
        System.out.println("原型对象id:" + prototype.getId()); // 1
        System.out.println("克隆对象id:" + cloneUser.getId()); // 1
        System.out.println("原型地址:" + prototype.getAddress().getCity()); // 北京
        System.out.println("克隆地址:" + cloneUser.getAddress().getCity()); // 北京

        // 4. 修改原型的引用对象属性 → 克隆对象的属性也会变(共享引用)
        addr.setCity("上海");
        System.out.println("修改后原型地址:" + prototype.getAddress().getCity()); // 上海
        System.out.println("修改后克隆地址:" + cloneUser.getAddress().getCity()); // 上海
    }
}
关键结论

浅克隆的问题:引用类型成员变量是 "共享" 的,修改原型的引用对象,克隆对象也会受影响

2. 深克隆(Deep Clone)
定义

不仅克隆基本数据类型,还会克隆所有引用类型成员变量(新对象和原型对象的引用类型成员变量是独立的)。

实现方式(常用 2 种)
方式 1:手动克隆引用对象

clone() 方法中,手动克隆引用类型成员变量:

复制代码
@Override
public User clone() {
    try {
        User cloneUser = (User) super.clone();
        // 手动克隆引用类型成员(深克隆核心)
        cloneUser.address = new Address(this.address.getCity());
        return cloneUser;
    } catch (CloneNotSupportedException e) {
        throw new AssertionError();
    }
}

测试结果:修改原型的 address,克隆对象的 address 不会变。

方式 2:序列化(推荐,适合复杂对象)

通过序列化将对象转为字节流,再反序列化为新对象(天然实现深克隆):

复制代码
// 需让User和Address实现Serializable接口
class User implements Serializable {
    private int id;
    private Address address;

    // 深克隆方法(序列化)
    public User deepClone() throws IOException, ClassNotFoundException {
        // 1. 序列化:将对象写入字节流
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);

        // 2. 反序列化:从字节流读取新对象
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (User) ois.readObject();
    }
}

class Address implements Serializable {
    private String city;
    // 构造函数+getter/setter
}

四、原型模式的优缺点

优点 缺点
1. 简化对象创建,避免重复初始化逻辑; 2. 提高创建效率(尤其对象初始化成本高时); 3. 隐藏对象创建细节,降低耦合; 1. 深克隆实现复杂(引用类型嵌套多时,手动克隆易遗漏); 2. 每个原型类都需实现克隆逻辑,增加代码量; 3. 需注意 Cloneable 接口的陷阱(未实现会抛异常);

五、总结

  1. 核心本质:原型模式是 "复制已有对象" 而非 "新建对象",核心解决 "对象创建成本高" 的问题;
  2. 关键区分:浅克隆共享引用对象(简单但有数据安全风险),深克隆完全独立(复杂但安全);
  3. 使用建议:简单对象用浅克隆,包含多层引用类型的复杂对象用序列化实现深克隆;
  4. 语言支持 :Java 通过 Cloneable + clone() 实现,Python 通过 copy 模块(copy.copy() 浅克隆、copy.deepcopy() 深克隆)实现,核心逻辑一致。
相关推荐
木心月转码ing1 天前
Hot100-Day24-T128最长连续序列
算法
Assby1 天前
从洋葱模型看Java与Go的设计哲学:为什么它们如此不同?
java·后端·架构
小肥柴1 天前
A2UI:面向 Agent 的声明式 UI 协议(三):相关概念和技术架构
算法
命运石之门的选择1 天前
Flink 并行度调优"黄金三步法"
后端
泰式大师1 天前
在 AI Agent 场景下,我们如何优雅地处理长文本?
后端
命运石之门的选择1 天前
Flink和CheckPoint简单了解
后端
Java水解1 天前
Python开发从入门到精通:Web框架Django实战
后端·python
回家路上绕了弯1 天前
OpenClaw 本地 AI 智能体全解析
后端·agent
belhomme1 天前
(面试题)Netty 线程模型
java·面试·netty
我爱娃哈哈1 天前
Spring Cloud Gateway + 请求聚合(GraphQL-like):一次调用合并多个微服务响应
后端