【设计模式】原型模型
·
【设计模式】原型模式
模拟场景:角色扮演游戏中的角色创建
一、优势简述
- 避免重复初始化:无需重复执行复杂的初始化过程
- 提升性能:通过复制现有对象,避免昂贵的资源消耗
- 支持动态配置:运行时动态修改对象并作为新原型
- 简化对象创建:客户端无需了解对象创建细节
- 支持深拷贝与浅拷贝:灵活控制对象复制粒度
二、解析
1. 避免重复初始化
在角色创建过程中,每个角色的技能树、装备等初始化逻辑复杂且耗时。使用原型模式,只需初始化一次,后续通过克隆快速生成。
- 原型对象完成一次完整初始化
- 克隆时复用已初始化的结构
- 大幅减少重复计算和资源加载
// 复杂初始化只需执行一次
private void initializeSkills() {
skills.add("Basic Attack");
if ("Warrior".equals(characterClass)) {
skills.add("Power Strike");
skills.add("Shield Bash");
} else if ("Mage".equals(characterClass)) {
skills.add("Fireball");
skills.add("Ice Shield");
}
}
克隆时直接复制已构建好的技能列表,无需再次判断职业并添加技能。
2. 提升性能
当需要批量创建相似角色时(如副本怪物、NPC),原型模式显著提升性能。
- 克隆操作远快于构造+初始化
- 适用于高频创建场景
- 减少GC压力(避免频繁对象分配)
// 高效批量创建
GameCharacter warriorPrototype = new GameCharacter("Warrior", "Warrior", 1);
List<GameCharacter> army = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
GameCharacter soldier = (GameCharacter) warriorPrototype.clone();
soldier.customize("Soldier-" + i, 1 + i % 10);
army.add(soldier);
}
对比:若每次 new GameCharacter(),需执行1000次 initializeSkills() 和 initializeEquipment()。
3. 支持动态配置
可以在运行时修改原型,影响后续所有克隆对象。
- 动态调整基础配置
- 实现“模板热更新”
- 支持A/B测试或多版本并行
// 动态调整原型
GameCharacter magePrototype = new GameCharacter("Mage", "Mage", 5);
magePrototype.addSkill("Lightning Bolt"); // 新增技能
magePrototype.getEquipment().put("Robe", "Arcane Robe");
// 后续所有克隆自动包含新配置
GameCharacter newMage = (GameCharacter) magePrototype.clone();
newMage.customize("Gandalf", 10);
4. 简化对象创建
客户端无需了解角色构建细节,只需克隆并定制。
- 解耦对象使用与创建
- 统一创建入口
- 易于扩展新角色类型
// 客户端代码简洁明了
CharacterPrototype prototype = getPrototype("Warrior");
CharacterPrototype character = prototype.clone();
character.customize("Conan", 8);
character.displayInfo();
无需关心 Warrior 的技能如何初始化,装备如何配置。
5. 支持深拷贝与浅拷贝
灵活控制复制粒度,确保对象独立性。
- 浅拷贝:引用类型共享(节省内存)
- 深拷贝:完全独立副本(安全独立)
@Override
public CharacterPrototype clone() throws CloneNotSupportedException {
GameCharacter clone = (GameCharacter) super.clone();
// 深拷贝确保独立性
clone.skills = new ArrayList<>(this.skills); // 独立技能列表
clone.equipment = new HashMap<>(this.equipment); // 独立装备映射
return clone;
}
⚠️ 若不深拷贝,修改一个角色的技能会影响所有克隆对象。
三、完整代码实现
1. 抽象原型接口
public interface CharacterPrototype extends Cloneable {
CharacterPrototype clone() throws CloneNotSupportedException;
void displayInfo();
void customize(String name, int level);
}
2. 具体原型类
import java.util.*;
public class GameCharacter implements CharacterPrototype {
private String name;
private final String characterClass; // 不可变属性
private int level;
private List<String> skills;
private Map<String, String> equipment;
public GameCharacter(String name, String characterClass, int level) {
this.name = name;
this.characterClass = characterClass;
this.level = level;
this.skills = new ArrayList<>();
this.equipment = new HashMap<>();
initializeSkills();
initializeEquipment();
}
private void initializeSkills() {
skills.add("Basic Attack");
switch (characterClass) {
case "Warrior":
skills.add("Power Strike");
skills.add("Shield Bash");
break;
case "Mage":
skills.add("Fireball");
skills.add("Ice Shield");
break;
case "Rogue":
skills.add("Backstab");
skills.add("Stealth");
break;
}
}
private void initializeEquipment() {
equipment.put("Weapon", getDefaultWeapon());
equipment.put("Armor", "Leather Armor");
if (level > 5) {
equipment.put("Accessory", "Silver Ring");
}
}
private String getDefaultWeapon() {
return switch (characterClass) {
case "Warrior" -> "Iron Sword";
case "Mage" -> "Wooden Staff";
case "Rogue" -> "Dagger";
default -> "Fists";
};
}
@Override
public CharacterPrototype clone() throws CloneNotSupportedException {
GameCharacter clone = (GameCharacter) super.clone();
// 深拷贝关键集合
clone.skills = new ArrayList<>(this.skills);
clone.equipment = new HashMap<>(this.equipment);
return clone;
}
@Override
public void displayInfo() {
System.out.println("=== Character Info ===");
System.out.println("Name: " + name);
System.out.println("Class: " + characterClass);
System.out.println("Level: " + level);
System.out.println("Skills: " + skills);
System.out.println("Equipment: " + equipment);
System.out.println("======================\n");
}
@Override
public void customize(String name, int level) {
this.name = name;
this.level = level;
// 根据等级调整装备
if (level > 5 && !equipment.containsKey("Accessory")) {
equipment.put("Accessory", "Silver Ring");
}
}
// 只读访问器(返回副本以保证封装)
public String getName() { return name; }
public String getCharacterClass() { return characterClass; }
public int getLevel() { return level; }
public List<String> getSkills() { return new ArrayList<>(skills); }
public Map<String, String> getEquipment() { return new HashMap<>(equipment); }
public void addSkill(String skill) {
if (!skills.contains(skill)) {
skills.add(skill);
}
}
}
3. 原型管理器(可选)
集中管理原型实例,支持注册与获取。
import java.util.HashMap;
import java.util.Map;
public class PrototypeRegistry {
private final Map<String, CharacterPrototype> prototypes = new HashMap<>();
public void addPrototype(String key, CharacterPrototype prototype) {
prototypes.put(key, prototype);
}
public CharacterPrototype getPrototype(String key) throws CloneNotSupportedException {
CharacterPrototype prototype = prototypes.get(key);
if (prototype != null) {
return prototype.clone();
}
throw new IllegalArgumentException("Unknown prototype: " + key);
}
}
4. 客户端测试代码
public class PrototypePatternDemo {
public static void main(String[] args) {
try {
// 创建基础原型
GameCharacter warriorProto = new GameCharacter("Warrior", "Warrior", 1);
GameCharacter mageProto = new GameCharacter("Mage", "Mage", 1);
// 使用原型克隆创建角色
GameCharacter hero1 = (GameCharacter) warriorProto.clone();
hero1.customize("Conan", 8);
GameCharacter hero2 = (GameCharacter) mageProto.clone();
hero2.customize("Merlin", 10);
hero2.addSkill("Teleport"); // 特殊技能
// 使用原型管理器
PrototypeRegistry registry = new PrototypeRegistry();
registry.addPrototype("Warrior", warriorProto);
registry.addPrototype("Mage", mageProto);
GameCharacter npc1 = (GameCharacter) registry.getPrototype("Warrior");
npc1.customize("Guard", 3);
GameCharacter npc2 = (GameCharacter) registry.getPrototype("Mage");
npc2.customize("Shopkeeper", 5);
// 展示所有角色
hero1.displayInfo();
hero2.displayInfo();
npc1.displayInfo();
npc2.displayInfo();
} catch (CloneNotSupportedException e) {
System.err.println("克隆失败: " + e.getMessage());
}
}
}
四、输出示例
=== Character Info ===
Name: Conan
Class: Warrior
Level: 8
Skills: [Basic Attack, Power Strike, Shield Bash]
Equipment: {Weapon=Iron Sword, Armor=Leather Armor, Accessory=Silver Ring}
======================
=== Character Info ===
Name: Merlin
Class: Mage
Level: 10
Skills: [Basic Attack, Fireball, Ice Shield, Teleport]
Equipment: {Weapon=Wooden Staff, Armor=Leather Armor, Accessory=Silver Ring}
======================
=== Character Info ===
Name: Guard
Class: Warrior
Level: 3
Skills: [Basic Attack, Power Strike, Shield Bash]
Equipment: {Weapon=Iron Sword, Armor=Leather Armor}
======================
=== Character Info ===
Name: Shopkeeper
Class: Mage
Level: 5
Skills: [Basic Attack, Fireball, Ice Shield]
Equipment: {Weapon=Wooden Staff, Armor=Leather Armor}
======================
五、适用场景总结
| 场景 | 说明 |
|---|---|
| 对象创建成本高 | 初始化复杂、依赖外部资源(文件、网络) |
| 需要大量相似对象 | 游戏NPC、报表模板、邮件批量发送 |
| 运行时动态配置 | A/B测试、配置热更新、多版本并行 |
| 避免子类爆炸 | 不同配置无需创建新类 |
| 保护原始对象 | 通过克隆隔离修改,保护原型完整性 |
✅ 最佳实践:结合工厂模式或注册表使用,实现更灵活的对象创建体系。
更多推荐
所有评论(0)