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

如何为含多选项的选择器类传递选项代码并迁移Switch逻辑

为菜单选项绑定独立逻辑,消除Switch语句的方案

现有问题与需求

你目前实现了一个MenuConstructor类用于生成控制台菜单,但每次使用都需要在外部编写switch语句处理选项逻辑,希望改成给每个选项单独绑定逻辑,调用runMenu即可自动执行对应动作,彻底摆脱重复的switch代码。

现有实现代码:

package lanta.utils;

import java.util.HashMap;
import java.util.Scanner;

public class MenuConstructor {
    public HashMap<Integer, String> options;
    public int option;
    public MenuConstructor(String defaultOption,String... options) {
        this.options = new HashMap<>();
        this.options.put(0, defaultOption);
        this.option = 1;
        for (String option : options) {
            this.options.put(this.option, option);
            this.option++;
        }
    }
    public MenuConstructor(HashMap<Integer, String> options) {
        this.options = options;
    }

    public int getOption(Scanner scanner) {
        StringBuilder message = new StringBuilder();
        message.append(0 + " - ").append(this.options.get(0));
        for(int i = 1; i < this.options.size(); i++){
            message.append(" | ").append(i).append(" - ").append(this.options.get(i));
        }
        System.out.println(message);
        System.out.println("Select an option:");
        String selection = scanner.nextLine().replaceAll("\\D.*", "");
        try {
            int selectedOption = Integer.parseInt(selection);
            if(options.containsKey(selectedOption)) return selectedOption;
            else {
                System.out.println("Invalid option, defaulting to 0");
                return 0;
            }
        } catch (NumberFormatException e) {
            System.out.println("Invalid number format, defaulting to 0");
            return 0;
        }
    }
}

你期望的调用方式(调整为可运行的Java代码形式):

Scanner scanner = new Scanner(System.in);
MenuConstructor menu = new MenuConstructor("Exit", "Say hello world", "Create a student");
// 绑定选项0的逻辑
menu.addAction(0, () -> {
    System.out.println("退出菜单");
    return -1; // 返回-1表示退出循环
});
// 绑定选项1的逻辑
menu.addAction(1, () -> {
    System.out.println("Hello world");
    return 0; // 返回0表示继续菜单循环
});
// 绑定选项2的逻辑
menu.addAction(2, () -> {
    Student student = new Student();
    System.out.println("学生对象已创建");
    return 0;
});
menu.runMenu(scanner);

解决方案:用函数式接口封装选项逻辑

核心思路是通过函数式接口将每个选项的逻辑封装成独立的动作,存储在菜单类中,无需外部switch语句,直接通过选项索引匹配并执行对应动作。

步骤1:定义函数式接口

先定义一个函数式接口,用来表示菜单选项的执行动作,返回值用于控制菜单循环:

@FunctionalInterface
public interface MenuAction {
    // 返回值规则:-1表示退出菜单,0表示继续显示菜单
    int execute();
}

步骤2:修改MenuConstructor类

新增存储动作的Map,添加绑定动作的方法,以及自动运行菜单的循环方法:

package lanta.utils;

import java.util.HashMap;
import java.util.Scanner;

public class MenuConstructor {
    // 存储选项文本
    private HashMap<Integer, String> optionTexts;
    // 存储选项对应的执行动作
    private HashMap<Integer, MenuAction> optionActions;

    public MenuConstructor(String defaultOption, String... options) {
        this.optionTexts = new HashMap<>();
        this.optionActions = new HashMap<>();
        // 初始化默认选项(索引0)
        this.optionTexts.put(0, defaultOption);
        int index = 1;
        for (String option : options) {
            this.optionTexts.put(index, option);
            index++;
        }
    }

    public MenuConstructor(HashMap<Integer, String> optionTexts) {
        this.optionTexts = optionTexts;
        this.optionActions = new HashMap<>();
    }

    // 为指定选项绑定执行动作
    public void addAction(int optionIndex, MenuAction action) {
        if (optionTexts.containsKey(optionIndex)) {
            this.optionActions.put(optionIndex, action);
        } else {
            throw new IllegalArgumentException("不存在索引为" + optionIndex + "的选项");
        }
    }

    // 获取用户选择的选项(私有方法,内部调用)
    private int getSelectedOption(Scanner scanner) {
        StringBuilder message = new StringBuilder();
        message.append(0).append(" - ").append(this.optionTexts.get(0));
        for (int i = 1; i < this.optionTexts.size(); i++) {
            message.append(" | ").append(i).append(" - ").append(this.optionTexts.get(i));
        }
        System.out.println(message);
        System.out.println("Select an option:");
        String selection = scanner.nextLine().replaceAll("\\D.*", "");
        try {
            int selectedOption = Integer.parseInt(selection);
            if (optionTexts.containsKey(selectedOption)) {
                return selectedOption;
            } else {
                System.out.println("无效选项,默认选择0");
                return 0;
            }
        } catch (NumberFormatException e) {
            System.out.println("输入格式错误,默认选择0");
            return 0;
        }
    }

    // 启动菜单循环
    public void runMenu(Scanner scanner) {
        while (true) {
            int selected = getSelectedOption(scanner);
            // 若未绑定动作,默认执行空动作(继续循环)
            MenuAction action = optionActions.getOrDefault(selected, () -> 0);
            int result = action.execute();
            // 返回-1则退出菜单循环
            if (result == -1) {
                break;
            }
        }
        scanner.close();
    }
}

步骤3:完整调用示例

现在可以按照你期望的方式调用,以下是可直接运行的示例代码:

import lanta.utils.MenuConstructor;
import java.util.Scanner;

public class MenuDemo {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        MenuConstructor menu = new MenuConstructor("Exit", "Say hello world", "Create a student");

        // 绑定选项0(退出)的逻辑
        menu.addAction(0, () -> {
            System.out.println("菜单已退出");
            return -1;
        });

        // 绑定选项1的逻辑
        menu.addAction(1, () -> {
            System.out.println("Hello world");
            return 0;
        });

        // 绑定选项2的逻辑
        menu.addAction(2, () -> {
            Student student = new Student();
            System.out.println("成功创建学生对象");
            return 0;
        });

        // 启动菜单
        menu.runMenu(scanner);
    }

    // 示例Student类
    static class Student {
        // 可添加类属性与方法
    }
}

思路说明

  • 用MenuAction函数式接口将每个选项的逻辑封装为独立的Lambda表达式,彻底消除了冗余的switch语句。
  • 菜单类专注于显示选项、获取输入、执行动作,外部只需绑定逻辑即可,符合单一职责原则。
  • 新增选项时,仅需添加文本并绑定对应动作,无需修改菜单类核心逻辑,符合开闭原则。

内容的提问来源于stack exchange,提问作者DuskFlare13

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.11 10:05:07