如何在Java中实现命令自动注册接口,无需每次新增if判断
实现方案
你可以通过注解+类路径扫描的机制实现命令自动注册,后续新增命令仅需加注解即可,不需要修改原有匹配逻辑,具体实现步骤如下:
步骤1:自定义命令标识注解
新增注解用于标记命令类对应的命令名称,运行时可被反射读取:
import java.lang.annotation.*; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Cmd { // 输入的命令字符串,比如print、exit String value(); }
步骤2:给现有命令类添加注解
给所有已实现的命令类加上@Cmd注解,示例:
@Cmd("print") public class Print extends Backend implements API, UI{ // 原有代码保持不变 @Override public boolean command() { System.out.println(string); return true; } @Override public API get() { return new Print(); } }
同理给Change加@Cmd("change")、Exit加@Cmd("exit")即可。
步骤3:修改UI接口的匹配逻辑
将原有硬编码的if判断替换为预加载的命令映射表,项目启动时自动扫描所有带@Cmd注解的命令类存入Map,匹配时直接从Map取值:
import java.io.File; import java.net.URISyntaxException; import java.net.URL; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.function.Function; public interface UI { API get(); // 预加载的命令映射表:key=命令名,value=对应命令类实例 Map<String, UI> CMD_MAP = loadCmdMap(); Function<String, UI> check = command -> CMD_MAP.getOrDefault(command, new NotFound()); static UI of(String command){ return check.apply(command); } // 扫描指定包下的所有命令类,加载到映射表 private static Map<String, UI> loadCmdMap() { Map<String, UI> cmdMap = new HashMap<>(); // 替换为你自己项目中命令类所在的包路径 String commandPackage = "com.yourproject.commands"; String packagePath = commandPackage.replace('.', '/'); try { Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(packagePath); while (resources.hasMoreElements()) { URL url = resources.nextElement(); File packageDir = new File(url.toURI()); // 遍历包下所有class文件 for (File classFile : packageDir.listFiles(f -> f.getName().endsWith(".class"))) { String className = classFile.getName().replace(".class", ""); Class<?> clazz = Class.forName(commandPackage + "." + className); // 筛选带@Cmd注解且实现了UI接口的类 if (clazz.isAnnotationPresent(Cmd.class) && UI.class.isAssignableFrom(clazz)) { Cmd cmdAnnotation = clazz.getAnnotation(Cmd.class); UI commandInstance = (UI) clazz.getDeclaredConstructor().newInstance(); cmdMap.put(cmdAnnotation.value(), commandInstance); } } } } catch (Exception e) { throw new RuntimeException("命令类加载失败,请检查包路径配置", e); } return cmdMap; } }
后续新增命令的操作
新增命令时只需要新建类,实现API和UI接口,加上@Cmd注解指定命令名即可,不需要修改任何其他代码:
// 新增hello命令示例 @Cmd("hello") public class Hello extends Backend implements API, UI{ @Override public boolean command() { System.out.println("Hello World!"); return true; } @Override public API get() { return new Hello(); } }
可选优化方案
如果不想自己实现类路径扫描逻辑,也可以引入Reflections第三方库简化扫描代码,或者使用Java内置的ServiceLoader实现,后者需要在META-INF/services目录下新增配置文件记录所有命令类的全限定名。
内容的提问来源于stack exchange,提问作者BroDep
相关产品推荐
相关产品推荐

