【从零入门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() 深克隆)实现,核心逻辑一致。
相关推荐
骄马之死6 小时前
SpringMVC + SpringBoot 核心知识点总结
java·spring boot·后端
zhengfei6117 小时前
第3章 Agent 类型分类与设计模式
设计模式
Frostnova丶7 小时前
【算法笔记】数学知识
笔记·算法
吴可可1237 小时前
AutoCAD 2016与2014二次开发关键差异
算法
GoGeekBaird7 小时前
Anthropic技能"(Skills)的经验分享
后端
王码码20358 小时前
多台服务器怎么统一看状态?Beszel 轻量监控,搭起来不费事
运维·服务器·后端·安全·阿里云·接口·web
刀法如飞8 小时前
一文搞懂DDD 领域驱动设计思想原理
设计模式·架构·代码规范
郑洁文8 小时前
基于Spring Boot的流浪动物救助网站
java·spring boot·后端·毕设·流浪动物救助
雨白8 小时前
哈希:以时间换空间的算法实战
算法