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

Java Menu类静态方法实现合理性及代码优化咨询

问题解答与代码优化建议

1. 静态方法是否为Menu类的最佳实践?面向对象替代方案

直接用全静态方法实现Menu类不属于Java最佳实践,核心问题包括:

  • 全局状态冲突:input、quitProgram这类静态变量会导致多场景调用时状态互相干扰,比如同时处理用户输入时出现混乱。
  • 无法扩展:静态方法不能被继承重写,后续要实现不同风格的菜单(如简化版、定制版)时,完全无法复用现有逻辑。
  • 违背面向对象思想:Menu是具备状态(当前菜单类型、运行状态)和行为(展示、输入处理)的实体,应该用实例类封装,而非静态工具类。

更符合面向对象的实现方案:

  • 将Menu设计为可实例化类,把菜单选项、输入Scanner、运行状态作为实例成员变量。
  • 针对不同角色(客户、管理员)创建Menu子类,或通过构造函数传入不同菜单选项集合,实现逻辑复用与扩展。
  • 把通用逻辑(如菜单展示、输入校验)抽为父类方法,子类仅需定义自身的选项和处理逻辑。

2. 当前代码是否遵循关注点分离原则?

当前代码完全不符合关注点分离原则,Menu类承担了至少4类职责:

  • 菜单内容定义(客户/管理员菜单选项)
  • 菜单展示逻辑
  • 用户输入读取与异常处理
  • 管理员登录的文件验证逻辑
  • 程序流程控制(切换界面、退出程序)

这种职责堆砌会导致维护成本剧增:比如修改登录逻辑时可能影响菜单展示,调整输入校验规则时要在多个方法中重复修改。


具体代码优化示例

第一步:拆分职责,创建专用类

  1. InputHandler类:统一处理用户输入,封装输入读取、异常校验逻辑,消除重复代码。
  2. AuthService类:单独处理管理员登录验证,把文件读取、账号校验逻辑从Menu中剥离。
  3. BaseMenu抽象类:定义菜单通用行为,子类实现具体的菜单选项和处理逻辑。

优化后的核心代码示例

InputHandler.java

import java.util.InputMismatchException;
import java.util.Scanner;

public class InputHandler {
    private final Scanner scanner;

    public InputHandler() {
        this.scanner = new Scanner(System.in);
    }

    public int getIntInput(String prompt, int min, int max) {
        int input;
        while (true) {
            System.out.print(prompt);
            try {
                input = scanner.nextInt();
                scanner.nextLine(); // 清除换行符
                if (input >= min && input <= max) {
                    return input;
                } else {
                    System.out.printf("请输入%d-%d之间的数字%n", min, max);
                }
            } catch (InputMismatchException e) {
                System.out.println("输入无效,请输入数字");
                scanner.nextLine(); // 清除无效输入
            }
        }
    }

    public String getStringInput(String prompt) {
        System.out.print(prompt);
        return scanner.nextLine();
    }

    public void close() {
        scanner.close();
    }
}

AuthService.java

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class AuthService {
    private static final String USER_FILE_PATH = "usernames.txt";
    private static final String PASS_FILE_PATH = "passwords.txt";

    public boolean validateAdmin(String username, String password) {
        File userFile = new File(USER_FILE_PATH);
        File passFile = new File(PASS_FILE_PATH);

        try (Scanner userScanner = new Scanner(userFile);
             Scanner passScanner = new Scanner(passFile)) {

            while (userScanner.hasNextLine() && passScanner.hasNextLine()) {
                String storedUser = userScanner.nextLine();
                String storedPass = passScanner.nextLine();
                if (storedUser.equals(username) && storedPass.equals(password)) {
                    return true;
                }
            }
        } catch (FileNotFoundException e) {
            System.out.println("账号文件未找到");
        }
        return false;
    }
}

BaseMenu.java

import java.util.List;

public abstract class BaseMenu {
    protected final InputHandler inputHandler;
    protected final AuthService authService;
    protected boolean isRunning;

    public BaseMenu(InputHandler inputHandler, AuthService authService) {
        this.inputHandler = inputHandler;
        this.authService = authService;
        this.isRunning = true;
    }

    protected abstract List<String> getMenuOptions();
    protected abstract void handleInput(int choice);

    public void run() {
        while (isRunning) {
            displayMenu();
            int choice = inputHandler.getIntInput("请输入选项编号:", 1, getMenuOptions().size());
            handleInput(choice);
        }
    }

    private void displayMenu() {
        System.out.println("\n=== 菜单 ===");
        for (String option : getMenuOptions()) {
            System.out.println(option);
        }
    }

    protected void quit() {
        isRunning = false;
        System.out.println("\n感谢使用果蔬管理系统");
        System.out.println("版权所有 Kerem Incorporated");
    }
}

CustomerMenu.java

import java.util.List;

public class CustomerMenu extends BaseMenu {
    public CustomerMenu(InputHandler inputHandler, AuthService authService) {
        super(inputHandler, authService);
    }

    @Override
    protected List<String> getMenuOptions() {
        return List.of(
                "1. 搜索商品目录",
                "2. 浏览商品目录",
                "3. 管理员登录",
                "4. 退出程序"
        );
    }

    @Override
    protected void handleInput(int choice) {
        switch (choice) {
            case 1 -> Catalog.searchTheCatalog();
            case 2 -> Catalog.browseTheCatalog();
            case 3 -> switchToAdminMenu();
            case 4 -> quit();
            default -> System.out.println("无效选项");
        }
    }

    private void switchToAdminMenu() {
        System.out.println("\n=== 管理员登录 ===");
        String username = inputHandler.getStringInput("请输入用户名:");
        String password = inputHandler.getStringInput("请输入密码:");

        if (authService.validateAdmin(username, password)) {
            System.out.println("欢迎进入管理员平台");
            AdminMenu adminMenu = new AdminMenu(inputHandler, authService);
            adminMenu.run();
        } else {
            System.out.println("用户名或密码错误");
        }
    }
}

AdminMenu.java

import java.util.List;

public class AdminMenu extends BaseMenu {
    public AdminMenu(InputHandler inputHandler, AuthService authService) {
        super(inputHandler, authService);
    }

    @Override
    protected List<String> getMenuOptions() {
        return List.of(
                "1. 添加商品",
                "2. 搜索商品目录",
                "3. 浏览商品目录",
                "4. 删除商品",
                "5. 退出程序"
        );
    }

    @Override
    protected void handleInput(int choice) {
        switch (choice) {
            case 1 -> Catalog.addFruitOrVegetableToCatalog();
            case 2 -> Catalog.searchTheCatalog();
            case 3 -> Catalog.browseTheCatalog();
            case 4 -> Catalog.removeProduct();
            case 5 -> quit();
            default -> System.out.println("无效选项");
        }
    }
}

程序入口类

public class Main {
    public static void main(String[] args) {
        InputHandler inputHandler = new InputHandler();
        AuthService authService = new AuthService();

        System.out.println("欢迎来到果蔬管理系统");
        System.out.print("请输入任意键继续...");
        inputHandler.getStringInput("");

        CustomerMenu customerMenu = new CustomerMenu(inputHandler, authService);
        customerMenu.run();

        inputHandler.close();
    }
}

优化后的优势
  • 职责清晰:每个类只专注单一功能,InputHandler管输入、AuthService管验证、BaseMenu管通用菜单逻辑、子类管具体菜单行为。
  • 可扩展性:新增菜单类型(如访客菜单)仅需继承BaseMenu实现,无需修改原有代码。
  • 无全局状态:所有状态为实例级别,多菜单实例不会互相干扰。
  • 代码复用:输入校验、菜单展示等通用逻辑在BaseMenu中统一实现,消除重复代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 17:40:57