Java如何根据方法入参动态调用对象方法,消除多类别适配的冗余代码
重复代码消除的可落地实现
优先方案:函数式方法映射
这是Java生态下适配动态方法调用的最优实现,没有反射开销,编译期可校验,完全不需要重复复制循环和判断逻辑。
实现步骤:
- 提前构建静态映射表,把传入的
categoryType字符串和Person类上对应的计算方法做一一绑定 - 循环逻辑完全复用原代码,只需要把原来硬编码的方法调用,替换成从映射表拿到的函数对象执行
代码示例:
// 提前初始化映射表,假设计算方法返回值为int类型,与firstPlace的判断类型匹配 private static final Map<String, Function<Person, Integer>> CATEGORY_EXECUTOR = Map.ofEntries( Map.entry("calculateCategoryOne", Person::calculateCategoryOne), Map.entry("calculateCategoryTwo", Person::calculateCategoryTwo), Map.entry("calculateCategoryThree", Person::calculateCategoryThree), // 剩余类别四到十的映射按同样格式补充即可 Map.entry("calculateCategoryTen", Person::calculateCategoryTen) ); public static void calculate(List<Person> data, String categoryType) { // 入参合法性校验,避免非法入参导致空指针 Function<Person, Integer> calcFunction = CATEGORY_EXECUTOR.get(categoryType); if (calcFunction == null) { throw new IllegalArgumentException("传入的类别计算类型不支持:" + categoryType); } // 原有循环逻辑完全不需要修改 for(int i = 0; i < categoryData.size(); i++) { // 替换原硬编码的方法调用为映射好的动态函数执行 if(calcFunction.apply(data.get(i)) == firstPlace) { // 原有的业务处理逻辑完全保留 } } }
这个方案的实际效果:后续新增类别只要在映射表里加一行对应关系,循环和判断逻辑永远不需要改动,没有重复代码,性能和原生写死的方法调用几乎没有差别。
次选方案:缓存式反射调用
如果不想维护方法引用映射表,可以通过反射根据传入的categoryType字符串定位目标方法,注意必须把反射获取到的Method对象做缓存,避免每次循环重复查找方法带来的性能损耗。
代码示例:
// 缓存反射获取到的方法对象,避免重复查找 private static final ConcurrentHashMap<String, Method> METHOD_CACHE = new ConcurrentHashMap<>(); public static void calculate(List<Person> data, String categoryType) { Method targetMethod = METHOD_CACHE.computeIfAbsent(categoryType, methodName -> { try { // 注意:传入的categoryType不要带括号,直接传纯方法名如"calculateCategoryOne",否则会匹配不到方法 Method m = Person.class.getMethod(methodName); m.setAccessible(true); return m; } catch (NoSuchMethodException e) { throw new IllegalArgumentException("未找到对应类别的计算方法:" + methodName, e); } }); for(int i = 0; i < categoryData.size(); i++) { int calcResult; try { calcResult = (int) targetMethod.invoke(data.get(i)); } catch (Exception e) { throw new RuntimeException("类别计算执行失败", e); } if(calcResult == firstPlace) { // 原有业务逻辑不变 } } }
这个方案的注意点:因为反射绕过编译期检查,如果传入的方法名字符串写错,要到运行时才会抛出异常,安全性低于函数式映射方案,仅适合不想修改原有方法引用配置的场景使用。
长期优化方向:统一方法入口
如果这些calculateCategoryOne到calculateCategoryTen的方法是在Person类中独立存在的,长期来看可以把这些方法整合成一个统一的计算入口,从根源上消除分散的重复方法:
- 在
Person类中新增统一计算方法,接收类别编号作为参数,内部代理调用原有的独立方法 - 业务侧只要把传入的
categoryType字符串解析成对应的类别编号,直接调用统一入口即可,不需要维护映射关系
代码示例:
// Person类中的统一入口 public int calculateCategory(int categoryIndex) { return switch (categoryIndex) { case 1 -> calculateCategoryOne(); case 2 -> calculateCategoryTwo(); case 3 -> calculateCategoryThree(); // 其余类别的分支按格式补充 default -> throw new IllegalArgumentException("不支持的类别编号:" + categoryIndex); }; } // 业务方法内的调用 public static void calculate(List<Person> data, String categoryType) { // 把传入的字符串解析为对应1-10的类别索引 int categoryIndex = parseCategoryIndex(categoryType); for(int i = 0; i < categoryData.size(); i++) { if(data.get(i).calculateCategory(categoryIndex) == firstPlace) { // 原有逻辑完全不变 } } }
内容的提问来源于stack exchange,提问作者leander
相关产品推荐
相关产品推荐

