模拟场景:角色扮演游戏中的角色创建


一、优势简述

  1. 避免重复初始化:无需重复执行复杂的初始化过程
  2. 提升性能:通过复制现有对象,避免昂贵的资源消耗
  3. 支持动态配置:运行时动态修改对象并作为新原型
  4. 简化对象创建:客户端无需了解对象创建细节
  5. 支持深拷贝与浅拷贝:灵活控制对象复制粒度

二、解析

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测试、配置热更新、多版本并行
避免子类爆炸不同配置无需创建新类
保护原始对象通过克隆隔离修改,保护原型完整性

最佳实践:结合工厂模式或注册表使用,实现更灵活的对象创建体系。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐