1. 模式概述
1.1 定义
原型模式(Prototype Pattern)是一种创建型设计模式,它通过复制现有对象(称为原型)来创建新对象,而不是通过new关键字实例化。该模式提供了一个原型接口,用于创建当前对象的克隆。
1.2 核心思想
**克隆(Clone)** 是原型模式的核心概念。当直接创建对象的成本较高时,通过复制现有对象来创建新对象可以显著提高性能,同时保持对象的初始状态。
2. 适用场景
| 场景 | 说明 | 示例 |
|---|---|---|
| 创建成本高 | 对象创建需要消耗大量资源 | 数据库连接、复杂计算对象 |
| 构造过程复杂 | 对象初始化需要多个步骤 | 配置对象、文档模板 |
| 状态相似对象 | 需要创建多个相似对象 | 游戏角色、简历模板 |
| 避免重复初始化 | 需要避免重复执行初始化代码 | 缓存对象、会话对象 |
3. 实现方式对比
3.1 浅克隆 vs 深克隆
| 特性 | 浅克隆 | 深克隆 |
|---|---|---|
| 基本数据类型 | 复制值 | 复制值 |
| 引用类型 | 复制引用 | 复制引用指向的对象 |
| 实现复杂度 | 简单 | 复杂 |
| 性能 | 高 | 较低 |
| 适用场景 | 无引用或引用不变 | 包含可变引用对象 |
3.2 Java实现方法对比
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
Cloneable.clone() |
简单、内置支持 | 只支持浅克隆 | 简单对象 |
| 手动深克隆 | 完全控制 | 代码复杂 | 复杂对象 |
| 序列化 | 自动深克隆 | 性能开销 | 需要序列化的对象 |
| 复制构造函数 | 类型安全 | 需要额外代码 | 替代clone() |
4. 完整代码实现
4.1 基础原型接口
/**
* 原型接口
* 声明克隆方法,所有具体原型必须实现
*/
public interface IPrototype extends Cloneable {
/**
* 克隆方法
* @return 克隆后的新对象
* @throws CloneNotSupportedException 当对象不支持克隆时抛出
*/
IPrototype clone() throws CloneNotSupportedException;
/**
* 深克隆方法
* @return 深克隆后的新对象
* @throws CloneNotSupportedException 当对象不支持克隆时抛出
*/
IPrototype deepClone() throws CloneNotSupportedException;
/**
* 显示对象信息
*/
void display();
}
4.2 具体原型类实现
import java.io.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 简历类 - 具体原型实现
* 演示浅克隆、深克隆、序列化克隆等多种实现方式
*/
public class Resume implements IPrototype, Serializable {
private static final long serialVersionUID = 1L;
// 基本类型字段
private String name;
private int age;
private String education;
// 引用类型字段
private Date birthDate;
private List<String> skills;
private WorkExperience workExperience;
/**
* 构造函数
*/
public Resume(String name, int age, String education) {
this.name = name;
this.age = age;
this.education = education;
this.birthDate = new Date();
this.skills = new ArrayList<>();
this.workExperience = new WorkExperience();
System.out.println("执行复杂的简历初始化过程...");
simulateComplexInitialization();
}
/**
* 复制构造函数 - 替代clone()的方法
*/
public Resume(Resume another) {
this.name = another.name;
this.age = another.age;
this.education = another.education;
this.birthDate = (Date) another.birthDate.clone();
this.skills = new ArrayList<>(another.skills);
this.workExperience = new WorkExperience(another.workExperience);
}
/**
* 模拟复杂初始化过程
*/
private void simulateComplexInitialization() {
try {
Thread.sleep(1000); // 模拟耗时操作
loadDefaultSkills();
initializeWorkExperience();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
private void loadDefaultSkills() {
skills.add("Java基础");
skills.add("面向对象编程");
}
private void initializeWorkExperience() {
workExperience.setCompany("未设置");
workExperience.setPosition("未设置");
workExperience.setYears(0);
}
//========== 克隆方法实现 ==========
/**
* 浅克隆实现
* 只复制基本数据类型和引用
*/
@Override
public Resume clone() throws CloneNotSupportedException {
System.out.println("执行浅克隆...");
return (Resume) super.clone();
}
/**
* 深克隆实现 - 方法1:手动复制
*/
@Override
public Resume deepClone() throws CloneNotSupportedException {
System.out.println("执行深克隆(手动)...");
Resume cloned = (Resume) super.clone();
// 深度复制所有引用类型字段
cloned.birthDate = (Date) this.birthDate.clone();
cloned.skills = new ArrayList<>(this.skills);
cloned.workExperience = this.workExperience.clone();
return cloned;
}
/**
* 深克隆实现 - 方法2:序列化
*/
public Resume deepCloneBySerialization() throws IOException, ClassNotFoundException {
System.out.println("执行深克隆(序列化)...");
// 将对象写入字节流
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
oos.flush();
// 从字节流读取对象
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (Resume) ois.readObject();
}
//========== 业务方法 ==========
public void addSkill(String skill) {
this.skills.add(skill);
}
public void setWorkExperience(String company, String position, int years) {
this.workExperience.setCompany(company);
this.workExperience.setPosition(position);
this.workExperience.setYears(years);
}
@Override
public void display() {
System.out.println("\n========== 简历详情 ==========");
System.out.println("姓名: " + name);
System.out.println("年龄: " + age);
System.out.println("学历: " + education);
System.out.println("出生日期: " + birthDate);
System.out.println("技能列表: " + String.join(", ", skills));
System.out.println("工作经历: " + workExperience);
System.out.println("对象哈希码: " + System.identityHashCode(this));
System.out.println("技能列表哈希码: " + System.identityHashCode(skills));
System.out.println("==============================\n");
}
//========== Getter和Setter ==========
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getEducation() { return education; }
public void setEducation(String education) { this.education = education; }
public List<String> getSkills() { return skills; }
public WorkExperience getWorkExperience() { return workExperience; }
}
/**
* 工作经验类 - 包含引用类型
*/
class WorkExperience implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
private String company;
private String position;
private int years;
private List<String> projects;
public WorkExperience() {
this.projects = new ArrayList<>();
}
public WorkExperience(WorkExperience another) {
this.company = another.company;
this.position = another.position;
this.years = another.years;
this.projects = new ArrayList<>(another.projects);
}
@Override
public WorkExperience clone() throws CloneNotSupportedException {
WorkExperience cloned = (WorkExperience) super.clone();
cloned.projects = new ArrayList<>(this.projects);
return cloned;
}
public void addProject(String project) {
this.projects.add(project);
}
@Override
public String toString() {
return String.format("%s - %s (%d年) 项目: %s",
company, position, years, String.join(", ", projects));
}
// Getter和Setter
public String getCompany() { return company; }
public void setCompany(String company) { this.company = company; }
public String getPosition() { return position; }
public void setPosition(String position) { this.position = position; }
public int getYears() { return years; }
public void setYears(int years) { this.years = years; }
public List<String> getProjects() { return projects; }
}
4.3 原型管理器(注册表)
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
/**
* 原型管理器(注册表)
* 管理预定义的原型对象,提供快速克隆
*/
public class PrototypeRegistry {
private static final Map<String, IPrototype> prototypes = new ConcurrentHashMap<>();
private static volatile PrototypeRegistry instance;
// 私有构造函数,单例模式
private PrototypeRegistry() {
initializeDefaultPrototypes();
}
/**
* 获取单例实例
*/
public static PrototypeRegistry getInstance() {
if (instance == null) {
synchronized (PrototypeRegistry.class) {
if (instance == null) {
instance = new PrototypeRegistry();
}
}
}
return instance;
}
/**
* 初始化默认原型
*/
private void initializeDefaultPrototypes() {
// Java开发人员模板
Resume javaDeveloper = new Resume("Java开发工程师", 25, "本科");
javaDeveloper.setWorkExperience("互联网公司", "Java开发", 3);
javaDeveloper.addSkill("Java");
javaDeveloper.addSkill("Spring Boot");
javaDeveloper.addSkill("MySQL");
javaDeveloper.addSkill("Redis");
javaDeveloper.getWorkExperience().addProject("电商系统");
prototypes.put("java-developer", javaDeveloper);
// 前端开发人员模板
Resume frontendDeveloper = new Resume("前端开发工程师", 24, "本科");
frontendDeveloper.setWorkExperience("科技公司", "前端开发", 2);
frontendDeveloper.addSkill("JavaScript");
frontendDeveloper.addSkill("Vue.js");
frontendDeveloper.addSkill("React");
frontendDeveloper.addSkill("TypeScript");
frontendDeveloper.getWorkExperience().addProject("后台管理系统");
prototypes.put("frontend-developer", frontendDeveloper);
// 项目经理模板
Resume projectManager = new Resume("项目经理", 32, "硕士");
projectManager.setWorkExperience("软件公司", "项目经理", 5);
projectManager.addSkill("项目管理");
projectManager.addSkill("团队协作");
projectManager.addSkill("敏捷开发");
projectManager.addSkill("需求分析");
projectManager.getWorkExperience().addProject("企业ERP系统");
prototypes.put("project-manager", projectManager);
}
/**
* 获取原型克隆
*/
public IPrototype getPrototype(String key) throws CloneNotSupportedException {
IPrototype prototype = prototypes.get(key);
if (prototype != null) {
return prototype.clone();
}
throw new IllegalArgumentException("未找到对应的原型: " + key);
}
/**
* 获取深克隆原型
*/
public IPrototype getDeepPrototype(String key) throws CloneNotSupportedException {
IPrototype prototype = prototypes.get(key);
if (prototype != null) {
return prototype.deepClone();
}
throw new IllegalArgumentException("未找到对应的原型: " + key);
}
/**
* 注册新原型
*/
public void registerPrototype(String key, IPrototype prototype) {
prototypes.put(key, prototype);
}
/**
* 移除原型
*/
public void removePrototype(String key) {
prototypes.remove(key);
}
/**
* 获取所有原型键
*/
public List<String> getAllPrototypeKeys() {
return new ArrayList<>(prototypes.keySet());
}
/**
* 清空所有原型
*/
public void clearAllPrototypes() {
prototypes.clear();
}
}
4.4 客户端使用示例
/**
* 客户端代码 - 演示原型模式的各种使用场景
*/
public class PrototypeClient {
public static void main(String[] args) {
try {
System.out.println("========== 原型模式演示 ==========\n");
// 1. 基本克隆演示
demonstrateBasicClone();
// 2. 浅克隆 vs 深克隆对比
demonstrateShallowVsDeepClone();
// 3. 原型注册表使用
demonstratePrototypeRegistry();
// 4. 性能对比测试
demonstratePerformanceComparison();
// 5. 序列化深克隆
demonstrateSerializationClone();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 1. 基本克隆演示
*/
private static void demonstrateBasicClone() throws CloneNotSupportedException {
System.out.println("1. 基本克隆演示");
System.out.println("=".repeat(40));
// 创建原始对象
Resume original = new Resume("张三", 28, "硕士");
original.setWorkExperience("阿里巴巴", "高级工程师", 5);
original.addSkill("分布式系统");
original.addSkill("微服务架构");
System.out.println("原始对象:");
original.display();
// 使用clone()方法克隆
Resume cloned = original.clone();
cloned.setName("李四");
cloned.setAge(30);
cloned.addSkill("云计算");
System.out.println("克隆对象(修改后):");
cloned.display();
System.out.println("原始对象(验证是否受影响):");
original.display();
}
/**
* 2. 浅克隆 vs 深克隆对比
*/
private static void demonstrateShallowVsDeepClone()
throws CloneNotSupportedException {
System.out.println("\n2. 浅克隆 vs 深克隆对比");
System.out.println("=".repeat(40));
// 创建包含引用类型的原始对象
Resume original = new Resume("王五", 26, "本科");
original.setWorkExperience("腾讯", "开发工程师", 3);
original.addSkill("Java");
original.getWorkExperience().addProject("社交应用");
System.out.println("原始对象:");
original.display();
// 浅克隆
Resume shallowClone = original.clone();
shallowClone.setName("浅克隆-王五");
shallowClone.getSkills().add("Python"); // 修改引用对象
shallowClone.getWorkExperience().addProject("即时通讯");
System.out.println("浅克隆对象(修改了引用对象):");
shallowClone.display();
System.out.println("原始对象(被浅克隆影响):");
original.display();
// 深克隆
Resume deepClone = original.deepClone();
deepClone.setName("深克隆-王五");
deepClone.getSkills().add("Go");
deepClone.getWorkExperience().addProject("游戏开发");
System.out.println("深克隆对象(修改了引用对象):");
deepClone.display();
System.out.println("原始对象(不受深克隆影响):");
original.display();
}
/**
* 3. 原型注册表使用
*/
private static void demonstratePrototypeRegistry()
throws CloneNotSupportedException {
System.out.println("\n3. 原型注册表使用");
System.out.println("=".repeat(40));
PrototypeRegistry registry = PrototypeRegistry.getInstance();
System.out.println("可用原型模板: " + registry.getAllPrototypeKeys());
// 使用Java开发人员模板
Resume javaDev = (Resume) registry.getPrototype("java-developer");
javaDev.setName("赵六");
javaDev.setAge(27);
javaDev.addSkill("Docker");
System.out.println("\n基于Java开发模板创建的简历:");
javaDev.display();
// 使用项目经理模板
Resume projectManager = (Resume) registry.getDeepPrototype("project-manager");
projectManager.setName("钱七");
projectManager.setAge(35);
projectManager.addSkill("成本控制");
System.out.println("\n基于项目经理模板创建的简历:");
projectManager.display();
// 注册新模板
Resume newTemplate = new Resume("全栈工程师", 28, "本科");
newTemplate.setWorkExperience("创业公司", "全栈开发", 4);
newTemplate.addSkill("Java");
newTemplate.addSkill("Vue.js");
newTemplate.addSkill("Linux");
registry.registerPrototype("fullstack", newTemplate);
System.out.println("新增原型后可用模板: " + registry.getAllPrototypeKeys());
}
/**
* 4. 性能对比测试
*/
private static void demonstratePerformanceComparison()
throws CloneNotSupportedException {
System.out.println("\n4. 性能对比测试");
System.out.println("=".repeat(40));
int count = 5;
// 测试new创建
long startTime = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
Resume resume = new Resume("测试", 25, "本科");
}
long newTime = System.currentTimeMillis() - startTime;
System.out.println("使用new创建" + count + "个对象耗时: " + newTime + "ms");
// 测试克隆创建
Resume template = new Resume("模板", 25, "本科");
startTime = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
Resume resume = template.clone();
resume.setName("克隆" + i);
}
long cloneTime = System.currentTimeMillis() - startTime;
System.out.println("使用clone创建" + count + "个对象耗时: " + cloneTime + "ms");
System.out.println("性能提升: " + (newTime - cloneTime) + "ms (" +
String.format("%.1f", (double)(newTime - cloneTime) / newTime * 100) + "%)");
}
/**
* 5. 序列化深克隆
*/
private static void demonstrateSerializationClone()
throws IOException, ClassNotFoundException {
System.out.println("\n5. 序列化深克隆演示");
System.out.println("=".repeat(40));
Resume original = new Resume("序列化测试", 30, "博士");
original.setWorkExperience("研究院", "研究员", 8);
original.addSkill("人工智能");
original.addSkill("机器学习");
original.getWorkExperience().addProject("智能推荐系统");
System.out.println("原始对象:");
original.display();
// 序列化深克隆
Resume serializedClone = original.deepCloneBySerialization();
serializedClone.setName("序列化克隆");
serializedClone.addSkill("深度学习");
serializedClone.getWorkExperience().addProject("图像识别");
System.out.println("序列化克隆对象:");
serializedClone.display();
System.out.println("原始对象(验证是否受影响):");
original.display();
}
}
5. 原型模式的扩展应用
5.1 与工厂模式结合
/**
* 原型工厂
* 结合工厂模式和原型模式
*/
public class PrototypeFactory {
public enum ResumeType {
JUNIOR_DEVELOPER,
SENIOR_DEVELOPER,
PROJECT_MANAGER,
TECH_LEAD
}
private static final Map<ResumeType, Resume> prototypes = new HashMap<>();
static {
prototypes.put(ResumeType.JUNIOR_DEVELOPER,
createResume("初级开发", 22, "本科", 1));
prototypes.put(ResumeType.SENIOR_DEVELOPER,
createResume("高级开发", 30, "硕士", 5));
prototypes.put(ResumeType.PROJECT_MANAGER,
createResume("项目经理", 35, "硕士", 8));
prototypes.put(ResumeType.TECH_LEAD,
createResume("技术负责人", 40, "博士", 10));
}
private static Resume createResume(String name, int age,
String education, int experience) {
Resume resume = new Resume(name, age, education);
resume.setWorkExperience("科技公司", getPositionByType(name), experience);
return resume;
}
private static String getPositionByType(String type) {
// 根据类型返回职位
return type;
}
public static Resume createResume(ResumeType type) throws CloneNotSupportedException {
Resume prototype = prototypes.get(type);
if (prototype != null) {
return prototype.clone();
}
throw new IllegalArgumentException("未知的简历类型: " + type);
}
public static Resume createDeepResume(ResumeType type) throws CloneNotSupportedException {
Resume prototype = prototypes.get(type);
if (prototype != null) {
return prototype.deepClone();
}
throw new IllegalArgumentException("未知的简历类型: " + type);
}
}
5.2 线程安全的原型模式
/**
* 线程安全的原型注册表
*/
public class ThreadSafePrototypeRegistry {
private final Map<String, IPrototype> prototypes = new ConcurrentHashMap<>();
private final ReadWriteLock lock = new ReentrantReadWriteLock();
/**
* 获取原型(线程安全)
*/
public IPrototype getPrototype(String key) throws CloneNotSupportedException {
lock.readLock().lock();
try {
IPrototype prototype = prototypes.get(key);
if (prototype == null) {
throw new IllegalArgumentException("原型不存在: " + key);
}
return prototype.clone();
} finally {
lock.readLock().unlock();
}
}
/**
* 注册原型(线程安全)
*/
public void registerPrototype(String key, IPrototype prototype) {
lock.writeLock().lock();
try {
prototypes.put(key, prototype);
} finally {
lock.writeLock().unlock();
}
}
}
6. 最佳实践建议
6.1 何时使用原型模式
| 场景 | 推荐实现 | 注意事项 |
|---|---|---|
| 对象创建成本高 | 使用原型模式 | 确保克隆比创建快 |
| 需要大量相似对象 | 使用原型注册表 | 注意内存占用 |
| 对象状态复杂 | 使用深克隆 | 处理好循环引用 |
| 需要避免构造约束 | 使用复制构造函数 | 保持代码清晰 |
6.2 克隆方法选择指南
public class CloneMethodSelector {
/**
* 根据场景选择克隆方法
*/
public enum CloneScenario {
SIMPLE_OBJECT, // 简单对象,无引用
COMPLEX_OBJECT, // 复杂对象,有引用
PERFORMANCE_CRITICAL, // 性能关键
THREAD_SAFE, // 线程安全
SERIALIZABLE // 需要序列化
}
/**
* 推荐的克隆方法
*/
public static CloneMethod getRecommendedMethod(CloneScenario scenario) {
switch (scenario) {
case SIMPLE_OBJECT:
return CloneMethod.SHALLOW_CLONE;
case COMPLEX_OBJECT:
return CloneMethod.DEEP_CLONE_MANUAL;
case PERFORMANCE_CRITICAL:
return CloneMethod.COPY_CONSTRUCTOR;
case THREAD_SAFE:
return CloneMethod.THREAD_SAFE_CLONE;
case SERIALIZABLE:
return CloneMethod.SERIALIZATION_CLONE;
default:
return CloneMethod.DEEP_CLONE_MANUAL;
}
}
public enum CloneMethod {
SHALLOW_CLONE, // 浅克隆
DEEP_CLONE_MANUAL, // 手动深克隆
DEEP_CLONE_SERIALIZATION, // 序列化深克隆
COPY_CONSTRUCTOR, // 复制构造函数
THREAD_SAFE_CLONE // 线程安全克隆
}
}
7. 注意事项和常见问题
7.1 常见问题及解决方案
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 浅克隆引用共享 | 引用类型只复制引用 | 实现深克隆 |
| 循环引用 | 对象相互引用 | 使用序列化或记录已克隆对象 |
| 性能问题 | 深克隆开销大 | 使用延迟复制或享元模式 |
| 线程安全问题 | 多线程访问原型 | 使用线程安全容器 |
7.2 代码规范建议
-
实现Cloneable接口:明确表明类支持克隆
-
重写clone()方法:访问修饰符改为public
-
提供深克隆选项:根据需要提供深克隆方法
-
文档说明:清晰说明克隆行为
-
单元测试:测试浅克隆和深克隆的正确性
8. 总结
原型模式是创建型模式中一种重要且实用的设计模式,特别适用于以下场景:
-
性能优化:当对象创建成本较高时
-
简化创建:避免复杂的对象初始化过程
-
动态配置:运行时决定对象的类型
-
状态保存:保存和恢复对象状态
在实际应用中,应根据具体需求选择合适的克隆策略,并结合其他设计模式(如工厂模式、建造者模式)以获得更好的设计效果。通过合理使用原型模式,可以显著提高系统性能,简化代码结构,提高代码的可维护性。