如何无需switch语句,根据用户输入创建子类并添加军队单位?
问题描述
我需要让用户选择要添加到军队中的单位,目前用switch语句实现,但后续要新增至少20种Unit子类,不断扩展case分支的方式效率极低,想寻找无需编写大量case语句的实现方案。
当前实现代码:
public class addToArmy { public void addUnit(ArrayList<Unit> units, String commander) { while (true) { System.out.println("Choose a unit"); String input = Battlefield.scanner.next(); switch (input) { case "Soldier": Soldier sd = new Soldier(commander); units.add(sd); return; case "Medic": Medic md = new Medic(commander); units.add(md); return; default: System.out.println("Not a valid unit"); } } } } // Soldier和Medic继承自抽象类Unit。
解决方案
1. 工厂映射表(推荐,安全易维护)
核心逻辑是用Map将用户输入字符串与对应的单位创建逻辑绑定,后续新增单位仅需向映射表中添加条目,无需修改原有核心代码。
示例实现:
import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.function.Function; // 修正类名符合Java规范 public class AddToArmy { // 预定义单位创建器映射 private static final Map<String, Function<String, Unit>> UNIT_CREATORS = new HashMap<>(); // 静态初始化块集中注册所有单位 static { UNIT_CREATORS.put("Soldier", Soldier::new); UNIT_CREATORS.put("Medic", Medic::new); // 新增单位直接追加一行即可 // UNIT_CREATORS.put("Archer", Archer::new); // UNIT_CREATORS.put("Tank", Tank::new); } public void addUnit(ArrayList<Unit> units, String commander) { while (true) { System.out.println("Choose a unit"); String input = Battlefield.scanner.next(); // 从映射表获取对应创建逻辑 Function<String, Unit> creator = UNIT_CREATORS.get(input); if (creator != null) { Unit unit = creator.apply(commander); units.add(unit); return; } else { System.out.println("Not a valid unit"); } } } }
该方案优势:
- 符合开闭原则,新增单位无需改动
addUnit核心逻辑 - 注册逻辑集中,便于统一管理所有可添加单位
- 类型安全,避免反射带来的风险
2. 枚举类封装单位信息
若需要给单位附加更多元数据(比如描述、快捷键),可使用枚举类封装单位的输入标识与创建逻辑:
import java.util.ArrayList; import java.util.function.Function; public class AddToArmy { // 枚举类统一管理单位信息 enum UnitType { SOLDIER("Soldier", Soldier::new), MEDIC("Medic", Medic::new), // 新增单位直接添加枚举项 // ARCHER("Archer", Archer::new); private final String inputName; private final Function<String, Unit> creator; UnitType(String inputName, Function<String, Unit> creator) { this.inputName = inputName; this.creator = creator; } // 根据用户输入匹配枚举项 public static UnitType fromInput(String input) { for (UnitType type : values()) { if (type.inputName.equalsIgnoreCase(input)) { // 支持大小写不敏感输入 return type; } } return null; } // 创建单位实例 public Unit create(String commander) { return creator.apply(commander); } } public void addUnit(ArrayList<Unit> units, String commander) { while (true) { System.out.println("Choose a unit"); String input = Battlefield.scanner.next(); UnitType type = UnitType.fromInput(input); if (type != null) { units.add(type.create(commander)); return; } else { System.out.println("Not a valid unit"); } } } }
该方案适合需要扩展单位属性的场景,例如遍历枚举值即可输出所有可选单位列表。
3. 反射实现(不推荐,存在安全风险)
若追求极致的“零配置”,可通过反射根据类名创建实例,但需注意类名与用户输入严格对应,且存在安全隐患:
import java.util.ArrayList; public class AddToArmy { public void addUnit(ArrayList<Unit> units, String commander) { while (true) { System.out.println("Choose a unit"); String input = Battlefield.scanner.next(); try { // 假设所有Unit子类在指定包下,例如com.yourgame.units Class<? extends Unit> unitClass = Class.forName("com.yourgame.units." + input).asSubclass(Unit.class); // 通过带String参数的构造方法创建实例 Unit unit = unitClass.getConstructor(String.class).newInstance(commander); units.add(unit); return; } catch (Exception e) { System.out.println("Not a valid unit"); } } } }
该方案缺点:
- 类型不安全,输入错误会抛出异常
- 依赖类名与输入严格匹配,重构类名将导致功能失效
- 存在安全风险,恶意输入可能执行危险代码
内容的提问来源于stack exchange,提问作者2naKyrielight
相关产品推荐
相关产品推荐

