import java.io.IOException; import java.util.List; import java.util.Optional; import java.util.Scanner; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 程序主入口和中央控制器。 * 负责管理应用生命周期、解析用户命令、协调各服务完成用户请求。 */ public class Application { // 依赖注入:在构造函数中初始化所有需要的服务 private final Scanner scanner; private final AuthService authService; private final SessionManager sessionManager; private final IFileService fileService; // 用于解析“切换为XX”命令的正则表达式 private static final Pattern SWITCH_COMMAND_PATTERN = Pattern.compile("^切换为(小学|初中|高中)$"); private static final int MIN_GENERATE_COUNT = 10; private static final int MAX_GENERATE_COUNT = 30; public Application() { this.scanner = new Scanner(System.in, "UTF-8"); // --- 依赖注入与组件装配 --- // 创建数据访问层的实例 UserRepository userRepository = new InMemoryUserRepository(); this.fileService = new TextFilePersistence(); // 创建应用服务层的实例,并注入依赖 this.authService = new AuthService(userRepository); // 获取会话管理器的单例实例 this.sessionManager = SessionManager.getInstance(); } /** * 启动并运行应用程序的主循环。 */ public void run() { System.out.println("欢迎使用中小学数学卷子自动生成程序!"); while (true) { if (!sessionManager.isUserLoggedIn()) { handleLoggedOutState(); } else { handleLoggedInState(); } } } /** * 处理用户未登录状态下的逻辑。 */ private void handleLoggedOutState() { System.out.print("请输入用户名和密码(以空格隔开,输入 'exit' 退出程序): "); String input = scanner.nextLine(); if ("exit".equalsIgnoreCase(input.trim())) { System.out.println("感谢使用,程序已退出。"); System.exit(0); } String[] credentials = input.split("\\s+"); if (credentials.length != 2) { System.out.println("输入格式错误,请输入正确的用户名、密码。"); return; } Optional userOptional = authService.login(credentials[0], credentials[1]); if (userOptional.isPresent()) { sessionManager.startSession(userOptional.get()); System.out.println("登录成功!欢迎您," + userOptional.get().getUsername() + "。"); } else { System.out.println("用户名或密码错误,请重试。"); } } /** * 处理用户已登录状态下的逻辑。 */ private void handleLoggedInState() { String currentLevelName = sessionManager.getCurrentLevelName(); System.out.printf( "当前选择为%s出题。请输入生成题目数量(%d-%d),或输入 '切换为XX',或输入 '-1' 退出登录:%n", currentLevelName, MIN_GENERATE_COUNT, MAX_GENERATE_COUNT); String input = scanner.nextLine().trim(); try { if ("-1".equals(input)) { handleLogout(); } else if (isSwitchCommand(input)) { handleSwitchLevel(input); } else if (isNumeric(input)) { int count = Integer.parseInt(input); validateGenerateCount(count); handleGenerateProblems(count); } else { throw new InvalidInputException( String.format("请输入小学、初中和高中三个选项中的一个", MIN_GENERATE_COUNT, MAX_GENERATE_COUNT)); } } catch (InvalidInputException | IOException | NumberFormatException e) { System.err.println("错误: " + e.getMessage()); } } private void handleLogout() { System.out.println("用户 " + sessionManager.getCurrentUser().getUsername() + " 已退出登录。"); sessionManager.endSession(); } private void handleSwitchLevel(String input) throws InvalidInputException { Matcher matcher = SWITCH_COMMAND_PATTERN.matcher(input); if (matcher.matches()) { String levelName = matcher.group(1); EducationLevel level = EducationLevel.fromLevelName(levelName); if (level != null) { sessionManager.setCurrentGenerator(level); System.out.println("成功切换到 " + levelName + " 出题模式。"); } else { // 这部分代码理论上不会执行,因为正则表达式已经限制了级别名称 throw new InvalidInputException("无效的切换目标级别。"); } } } private void handleGenerateProblems(int count) throws IOException { User currentUser = sessionManager.getCurrentUser(); System.out.println("正在加载历史题目,请稍候..."); Set history = fileService.loadAllProblemHistory(currentUser); System.out.println("历史题目加载完毕。共找到 " + history.size() + " 道历史题目。"); System.out.println("正在生成 " + count + " 道不重复的新题目..."); IProblemGenerator generator = sessionManager.getCurrentGenerator(); List newProblems = generator.generate(count, history); System.out.println("题目生成完毕,正在保存到文件..."); fileService.saveProblems(currentUser, newProblems); System.out.println("保存成功!新的题目已存储在用户目录 " + currentUser.getStoragePath() + " 下。"); } private boolean isSwitchCommand(String input) { return SWITCH_COMMAND_PATTERN.matcher(input).matches(); } private boolean isNumeric(String str) { return str != null && str.matches("-?\\d+"); } private void validateGenerateCount(int count) throws InvalidInputException { if (count < MIN_GENERATE_COUNT || count > MAX_GENERATE_COUNT) { throw new InvalidInputException( String.format("生成数量必须在 %d 到 %d 之间。", MIN_GENERATE_COUNT, MAX_GENERATE_COUNT)); } } public static void main(String[] args) { Application app = new Application(); app.run(); } }