祝大家除夕快乐新年发大财!!!
一、原型模式的核心定义
原型模式是一种创建型设计模式 ,核心思想是:基于一个已存在的 "原型对象",通过 "克隆(复制)" 的方式创建新对象,而非通过 new 关键字从头初始化。可以类比成 "复印文件":已有一份写好的文件(原型),想要多份相同的文件时,直接复印(克隆)比重新手写(new + 初始化)效率高得多。
二、核心适用场景
当满足以下条件时,优先考虑原型模式:
- 对象创建成本高(比如初始化需要大量 IO 操作、数据库查询、网络请求);
- 需要频繁创建结构 / 属性相似的对象;
- 希望隐藏对象创建的复杂细节,只关注 "复制已有对象";
- 避免构造函数的复杂逻辑(比如构造函数参数过多、逻辑嵌套)。
三、实现方式(以 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 接口的陷阱(未实现会抛异常); |
五、总结
- 核心本质:原型模式是 "复制已有对象" 而非 "新建对象",核心解决 "对象创建成本高" 的问题;
- 关键区分:浅克隆共享引用对象(简单但有数据安全风险),深克隆完全独立(复杂但安全);
- 使用建议:简单对象用浅克隆,包含多层引用类型的复杂对象用序列化实现深克隆;
- 语言支持 :Java 通过
Cloneable+clone()实现,Python 通过copy模块(copy.copy()浅克隆、copy.deepcopy()深克隆)实现,核心逻辑一致。
