You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何无需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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 16:45:12