原型模式 (Prototype) 全面讲解
学习笔记
设计模式
原型模式
Java
面向对象
克隆
对象创建
设计模式讲解
本文全面讲解了原型模式,包括其定义、适用场景、结构以及示例代码。文章深入探讨了原型模式在Java中的应用,并提供了具体的实现示例。
date: 2025-06-22T19:44:00 tags:
- 复习
- Java
- 设计模式
- 面向对象
原型模式 (Prototype) 全面讲解
1. 什么是原型模式?
原型模式是创建型设计模式,通过**复制现有对象(原型)**来创建新对象,而非通过new实例化。
- 核心思想:克隆(Clone)代替重新构造,适用于创建成本高或构造过程复杂的对象。
- 类比:细胞分裂(基于现有细胞复制新细胞)。
🔹 适用场景
- 对象创建开销大(如数据库查询结果、复杂计算对象)。
- 需要动态配置对象的初始状态(如游戏中的敌人/NPC生成)。
2. 为什么需要原型模式?
问题场景
假设有一个Enemy类,构造时需要从数据库加载属性:
// 传统方式:每次new都需重复耗时操作
Enemy enemy1 = new Enemy(); // 耗时:数据库查询+初始化
Enemy enemy2 = new Enemy(); // 再次耗时...
解决方案
通过克隆第一个实例快速创建后续对象:
Enemy prototype = new Enemy(); // 仅第一次耗时
Enemy enemy2 = prototype.clone(); // 直接复制内存,极快
3. 原型模式的结构
角色说明
Prototype(抽象原型):声明克隆方法的接口(Java中通常是Cloneable)。ConcretePrototype(具体原型):实现克隆方法的具体类。
4. 示例代码(游戏敌人克隆)
步骤1:实现Cloneable接口
public class Enemy implements Cloneable {
private String type;
private int health;
private List<String> weapons;
public Enemy(String type, int health) {
this.type = type;
this.health = health;
this.weapons = loadWeaponsFromDatabase(); // 模拟耗时操作
System.out.println("耗时:从数据库加载武器数据");
}
// 模拟复杂初始化
private List<String> loadWeaponsFromDatabase() {
return Arrays.asList("Sword", "Shield");
}
// 关键:重写clone()方法
@Override
public Enemy clone() {
try {
Enemy cloned = (Enemy) super.clone(); // 浅拷贝
cloned.weapons = new ArrayList<>(this.weapons); // 手动深拷贝可变字段
return cloned;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
public void attack() {
System.out.println(type + "攻击!武器:" + weapons);
}
}
步骤2:客户端调用
public class Client {
public static void main(String[] args) {
// 原始对象(构造耗时)
Enemy original = new Enemy("Dragon", 100);
// 通过克隆快速创建新对象
Enemy clone1 = original.clone();
Enemy clone2 = original.clone();
original.attack(); // Dragon攻击!武器:[Sword, Shield]
clone1.attack(); // Dragon攻击!武器:[Sword, Shield]
}
}
5. 关键点总结
🔹 浅拷贝 vs 深拷贝
| 类型 | 实现方式 | 特点 |
|---|---|---|
| 浅拷贝 | super.clone() | 复制基本类型字段,引用类型字段共享内存(修改会影响原对象)。 |
| 深拷贝 | 手动复制引用类型 | 完全独立的对象,需递归处理所有引用字段(如集合、自定义类)。 |
🔹 原型模式的优点
- 性能高:避免重复初始化耗时操作。
- 动态配置:克隆后可修改部分属性(如
clone.setHealth(50))。
🔹 注意事项
- Java的
Cloneable是标记接口,需主动重写clone()方法。 - 深拷贝需谨慎处理循环引用问题。
6. 互动实践
问题1:以下代码是浅拷贝还是深拷贝?
@Override
public Enemy clone() {
try {
return (Enemy) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
答案:浅拷贝!weapons字段(List)与原对象共享内存。
问题2:如何实现Weapon类的深拷贝?
任务:假设Enemy包含Weapon对象:
public class Weapon implements Cloneable {
private String name;
@Override
public Weapon clone() { /* 你的代码 */ }
}
// 修改Enemy.clone()实现完全深拷贝
7. 考试练习题
题目1(概念题)
原型模式的核心目的是什么?
A. 隐藏对象创建细节
B. 通过复制现有对象创建新实例
C. 限制类的实例化次数
D. 替代继承
答案:B
题目2(代码填空)
补全原型模式的深拷贝代码:
public class Student implements Cloneable {
private String name;
private List<String> courses;
@Override
public Student clone() {
try {
Student cloned = (Student) super.clone();
cloned.courses = ____; // 填空1(深拷贝courses)
return cloned;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
答案:new ArrayList<>(this.courses)
题目3(设计题)
用原型模式设计一个Document类,支持克隆:
- 属性:
title(字符串)、pages(List<String>) - 要求:实现深拷贝,并说明如何避免循环引用问题。