《原型模式》|设计模式系列第06篇
系列:创建型模式 · 原型模式(Prototype Pattern)
关键词:对象克隆、浅拷贝、深拷贝、原型实例、减少new开销
一、什么是原型模式
原型模式(Prototype Pattern):用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。

属于创建型设计模式。
简单理解:
不再通过 new 新建对象,而是拿一个现成对象当模板,直接复制克隆一份。适合对象创建成本高的场景,规避构造函数执行开销。
核心意图
降低对象创建成本;复用已有对象的数据,快速生成新实例。
适用场景
- 对象创建开销大(初始化耗时、读取数据库/文件、网络加载)
- 需要大量相似对象,对象之间仅有少量字段差异
- 不想暴露复杂对象创建逻辑给客户端
- 动态获取对象类型,运行时复制实例
⚠️ 缺点预警:需要合理处理浅拷贝与深拷贝;对象包含循环引用时克隆逻辑复杂。
二、UML结构图
角色划分:
- Prototype(抽象原型):声明克隆方法,一般提供
clone() - ConcretePrototype(具体原型):实现克隆方法,复制自身生成新对象
- Client(客户端):获取原型对象,调用克隆方法生成新实例

三、Java 完整示例
Java 原生提供 Cloneable 标记接口,重写 clone() 方法实现原型。
注意:
Object.clone()默认是浅拷贝。
1. 具体原型类(浅拷贝示例)
public class User implements Cloneable {
private String username;
private int age;
private Address address;
public User(String username, int age, Address address) {
this.username = username;
this.age = age;
this.address = address;
}
@Override
protected User clone() throws CloneNotSupportedException {
return (User) super.clone();
}
// getter & setter
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", age=" + age +
", address=" + address +
'}';
}
}
// 引用类型成员
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;
}
@Override
public String toString() {
return "Address{" +
"city='" + city + '\'' +
'}';
}
}
2. 客户端调用
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address("杭州");
User prototype = new User("张三", 20, address);
// 克隆原型对象
User cloneUser = prototype.clone();
System.out.println("原型对象:" + prototype);
System.out.println("克隆对象:" + cloneUser);
// 浅拷贝:引用对象地址是同一个
cloneUser.getAddress().setCity("上海");
System.out.println("修改克隆对象地址后,原型对象:" + prototype);
}
}
运行结果可以看到:修改克隆对象里的引用类型 Address,原型对象的地址也跟着变化,这就是浅拷贝。
3. 改造为深拷贝
修改 User 的 clone 方法,把引用对象也单独克隆一份:
@Override
protected User clone() throws CloneNotSupportedException {
User user = (User) super.clone();
// 引用类型单独拷贝
user.address = new Address(address.getCity());
return user;
}
此时修改克隆对象的 Address,不会影响原型对象。
四、浅拷贝 vs 深拷贝
- 浅拷贝:复制基本数据类型;引用类型只复制对象引用地址,共用同一个引用对象。
- 深拷贝:基本类型、引用类型全部新建独立对象,新旧对象完全隔离,互不干扰。
实现深拷贝可选方案:
- 手动在 clone 方法中递归拷贝引用对象
- 对象序列化/反序列化(Jackson,Java原生序列化)
五、优缺点总结
✅ 优点
- 克隆比 new 性能更高,适合创建开销大的对象
- 简化对象创建流程,客户端直接复制原型
- 动态新增/修改原型,灵活生成相似对象
❌ 缺点
- 需要编写克隆逻辑,尤其深拷贝实现繁琐
- 存在循环引用时,克隆逻辑很难处理
- 每一个原型类都需要支持克隆,需要改造原有代码
六、原型模式与其他创建型模式对比
| 模式 | 创建方式 | 核心特点 |
|---|---|---|
| 工厂/建造者 | new 创建对象 | 侧重于对象组装与实例化 |
| 原型模式 | 克隆复制对象 | 基于已有实例复制,规避昂贵构造 |
七、框架源码应用
- JDK
java.util.ArrayList.clone() - Spring 中原型 Bean(scope=”prototype”),每次获取返回全新实例,思想源自原型模式
- Apache Commons 工具类提供原型克隆工具
八、小结
原型模式核心:以现有对象作为模板进行克隆复制。
重点区分浅拷贝与深拷贝;对象内部存在引用类型时,一定要评估拷贝方式带来的副作用。
适合对象初始化成本高,大量相似实例场景。
0 条笔记