以面向对象的思维和软件架构完成一道编程题目(Java)–原作者:小康小白–重写

  • Post author:
  • Post category:java


今天刚好没事,看了下CSDN,看到有这个题,一时兴起就做了一下

原文链接:https://blog.csdn.net/weixin_45791445/article/details/108890171

作者是:小康小白

开始看的时候感觉很简单,半天就可以写完了,写着写着突然想尝试一下NIO来代替普通IO流,不太熟悉缓冲区结构,查了点资料,加调错,结果就花了一天时间。。

当然,我知道NIO只是在读大文件时候会用到,在读小文件的时候,效率还比不上普通IO流,不过既然是练习,尝试一下新的API也是一种提升

如果是正式项目,我会把所有的静态变量提取到配置文件中,或者单独写在一个constant类中统一保存,而不是直接写在业务类中

下面贴一下代码,写完我也没细看了,有可以优化的地方希望大佬提出来,小弟学习一下

由于在控制台完成,也不涉及数据库,所以总共是2个类,一个是实体类,一个是业务类。业务类由于太长,建议拷贝到IDE工具中再看方便一些

实体类:

import java.util.List;

public class ExamResultBO {
    /**
     * 学生编号
     */
    private String id;
    /**
     * 试题
     */
    private List<String> examQuestions;
    /**
     * 学生的选项
     */
    private List<String> choice;
    /**
     * 试题的正确答案
     */
    private List<String> correctAnswer;
    /**
     * 每一题的得分,由于这里不需要每一题的分数,所以就只记录总分
     */
    private int score;
    /**
     * 完成答题所花费的时间
     */
    private long spendTime;
    
    //下面是get和set方法,就不贴了
}

业务类:

import com.dahua.practise.pojo.ExamResultBO;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.util.*;

public class StudentMath {
    /**
     * 1.1【问题描述】
     * 编写一个帮助小学生练习数学的程序,帮助小学生练习100以内的四种数学运算:加、减、乘、除。
     * 1.2【基本要求】
     * a) 程序应先询问用户的ID号(ID号包括两个大写字母和4位数字),例如:
     * 请输入用户ID号:AB1234 程序应对输入的ID号验证,符合ID号要求的格式,然后程序提示三种选择: (1)开始测试 (2)检查分数 (3)退出
     * b) 测试:该程序将给出10道数学题,例如:
     * 12 * 3 =36
     * 48 + 32 =80
     * 56 / 28 =2
     * 注意:
     * i)学生将依次回答每一个问题(在等于号后面给出答案),然后给出下一道题。
     * ii)试题应包含四种数学运算:加、减、乘、除,它们是随机产生的。相邻的问题应该是不同的操作,每个操作必须至少出现一次。
     * iii)为每道题随机生成数字,但必须确保参与运算的数字和结果都小于100且大于零的整数。
     * iv)十道题做完后,记录学生完成这十道题所用的时间。
     * v)给每个学生一个分数。将该学生的ID、成绩和使用时间保存到一个名为record.txt的文件中。
     * vi)在屏幕上输出以下信息:
     * 问题 | 正确答案 | 你的答案
     * c) 成绩检查:从文件“record.txt”中列出该学生的所有历史成绩。例如:
     * 你以前的记录是:
     * AB1234 80 150秒
     * AB1234 50 182秒
     * AB1234 90 98秒
     */
    //生成题目的数量
    private static final int QUESTION_NUM = 5;
    private static final int TOTAL_SCORE = 100;
    private static final String FILE_PATH = "D:/result.txt";
    
    public static void main(String[] args) {
        //检测用户名
        String user = checkUserId();
        //给提示做出选择,(1)开始测试 (2)检查分数 (3)退出
        boolean repeatFlag = true;
        while (repeatFlag) {
            System.out.println("请做出选择:(1)开始测试 (2)检查分数 (3)退出");
            String choice = new Scanner(System.in).nextLine();
            switch (choice) {
                case "1":
                    exam(user);
                    repeatFlag = false;
                    break;
                case "2":
                    checkScore(user);
                    repeatFlag = false;
                    break;
                case "3":
                    repeatFlag = false;
                    break;
                default:
                    System.out.println("您的输入有误,请重新输入");
                    break;
            }
        }
    }
    
    private static void exam(String user) {
        //生成计算过程,更新考试结果resultMap,并且需要拿到一个用于屏幕显示的Map
        ExamResultBO examResult = manageExam();
        examResult.setId(user);
        //展示结果
        System.out.println("问题\t正确答案\t你的答案");
        for (int i = 0; i < QUESTION_NUM; i++) {
            System.out.println(examResult.getExamQuestions().get(i) + "\t" +
                    examResult.getCorrectAnswer().get(i) + "\t" +
                    examResult.getChoice().get(i));
        }
        //序列化结果到磁盘
        NIOWrite(examResult);
    }
    
    /**
     * 序列化结果到磁盘
     *
     * @param examResult 考试结果
     */
    private static void NIOWrite(ExamResultBO examResult) {
        FileOutputStream fos = null;
        try {
            File file = new File(FILE_PATH);
            fos = new FileOutputStream(file, true);
            FileChannel channel = fos.getChannel();
            ByteBuffer bufferHead = StandardCharsets.UTF_8.encode("小学生一百以内加减法测试题\n");
            String body = examResult.getId() + "\t" + examResult.getScore() + "\t" +
                    examResult.getSpendTime() + "\n";
            ByteBuffer bufferBody = StandardCharsets.UTF_8.encode(body);
            if (file.length() == 0) {
                channel.write(bufferHead);
            }
            channel.write(bufferBody);
            channel.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    /**
     * 生成计算的过程
     */
    private static ExamResultBO manageExam() {
        Random random = new Random();
        Scanner scanner = new Scanner(System.in);
        //需要返回用于展示的map
        ExamResultBO result = new ExamResultBO();
        List<String> examQuestions = new ArrayList<>();
        List<String> studentAnswer = new ArrayList<>();
        List<String> correctAnswer = new ArrayList<>();
        
        int scorePerQuestion = TOTAL_SCORE / QUESTION_NUM;
        int getScore = 0;
        
        //参与计算的两个数字
        int a = 0;
        int b = 0;
        //要求加减乘除都必须出先至少1次
        List<Integer> optList = getOptList();
        long startTime = System.currentTimeMillis();
        //开始测验
        for (int i = 0; i < QUESTION_NUM; i++) {
            int finalI = i;
            int opt = Optional.ofNullable(optList).map(list -> list.get(finalI)).orElse(-1);
            String question = "";
            String answer = "";
            switch (opt) {
                case 0:
                    //不计算超过100的加法
                    do {
                        a = random.nextInt(99) + 1;
                        b = random.nextInt(99) + 1;
                    } while (a + b > 100);
                    question = a + " + " + b + " = ";
                    System.out.print(question);
                    answer = scanner.nextLine();
                    //写入到结果集中,其中userId拿到外部补充
                    examQuestions.add(question);
                    studentAnswer.add(answer);
                    correctAnswer.add("" + (a + b));
                    getScore += ("" + (a + b)).equals(answer) ? scorePerQuestion : 0;
                    break;
                case 1:
                    //不计算负数
                    do {
                        a = random.nextInt(99) + 1;
                        b = random.nextInt(99) + 1;
                    } while (a - b < 0);
                    question = a + " - " + b + " = ";
                    System.out.print(question);
                    answer = scanner.nextLine();
                    examQuestions.add(question);
                    studentAnswer.add(answer);
                    correctAnswer.add("" + (a - b));
                    getScore += ("" + (a - b)).equals(answer) ? scorePerQuestion : 0;
                    break;
                case 2:
                    //不计算超过100的乘法
                    do {
                        a = random.nextInt(99) + 1;
                        b = random.nextInt(99) + 1;
                    } while (a * b > 100);
                    question = a + " * " + b + " = ";
                    System.out.print(question);
                    answer = scanner.nextLine();
                    examQuestions.add(question);
                    studentAnswer.add(answer);
                    correctAnswer.add("" + (a * b));
                    getScore += ("" + (a * b)).equals(answer) ? scorePerQuestion : 0;
                    break;
                case 3:
                    //只生成可以整除的a和b
                    do {
                        a = random.nextInt(99) + 1;
                        b = random.nextInt(99) + 1;
                    } while (a % b != 0);
                    
                    question = a + " / " + b + " = ";
                    System.out.print(question);
                    answer = scanner.nextLine();
                    examQuestions.add(question);
                    studentAnswer.add(answer);
                    correctAnswer.add("" + (a / b));
                    getScore += ("" + (a / b)).equals(answer) ? scorePerQuestion : 0;
                    break;
                default:
                    break;
            }
        }
        result.setSpendTime(System.currentTimeMillis() - startTime);
        result.setExamQuestions(examQuestions);
        result.setChoice(studentAnswer);
        result.setCorrectAnswer(correctAnswer);
        result.setScore(getScore);
        return result;
    }
    
    private static List<Integer> getOptList() {
        if (QUESTION_NUM < 4) {
            throw new IllegalArgumentException("题目数量少于4,无法生成");
        }
        List<Integer> resultList = new ArrayList<>(QUESTION_NUM);
        List<Integer> staticList = Arrays.asList(0, 1, 2, 3);
        List<Integer> randomList = new ArrayList<>(QUESTION_NUM - 4);
        
        Random random = new Random();
        for (int i = 0; i < QUESTION_NUM - 4; i++) {
            int a = random.nextInt(4);
            randomList.add(a);
        }
        resultList.addAll(staticList);
        resultList.addAll(randomList);
        if (CollectionUtils.isEmpty(resultList)) {
            return null;
        }
        //重新打乱排序
        Collections.shuffle(resultList);
        return resultList;
    }

    private static void checkScore(String user) {
        //这里得到的结果集已经完成用户名匹配
        List<ExamResultBO> resultList = readFile(user);
        if (CollectionUtils.isEmpty(resultList)){
            System.out.println("系统中没有你的考试记录,请先进行一次考试");
            return;
        }
        System.out.println("你以前的记录是:");
        for (ExamResultBO result : resultList) {
            System.out.println(result.getId() + " " + result.getScore() + " " + result.getSpendTime() / 1000 + "秒");
        }
    }
    
    private static List<ExamResultBO> readFile(String user) {
        File file = new File(FILE_PATH);
        String str = null;
        FileInputStream fis = null;
        List<ExamResultBO> examResultList = new ArrayList<>();
        try {
            fis = new FileInputStream(file);
            FileChannel channel = fis.getChannel();
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            
            byte[] bytes = new byte[0];
            while (channel.read(buffer) != -1) {
                //读取到缓冲区数组
                byte[] readBytes = buffer.array();
                //保存循环开始时上一个byte[]的长度
                int oldLength = bytes.length;
                //把byte[]长度扩充到缓冲区position指针的长度
                bytes = Arrays.copyOf(bytes, bytes.length + buffer.position());
                //把读取的数据放入bytes[],注意界限是position指针位置,防止最后一行出现其他数据
                System.arraycopy(readBytes, 0, bytes, oldLength, buffer.position());
                //初始化buffer指针
                buffer.clear();
            }
            str = new String(bytes);
            //对str进行封装
            String[] arr = str.split("\n");
            for (String s : arr) {
                if (!s.contains("\t")) {
                    //如果是第一行,则不包含制表符
                    continue;
                }
                ExamResultBO examResult = new ExamResultBO();
                String[] val = s.split("\t");
                if (user.equals(val[0])) {
                    //结果集中只写入匹配用户名的记录
                    examResult.setId(val[0]);
                    examResult.setScore(Integer.parseInt(val[1]));
                    examResult.setSpendTime(Long.parseLong(val[2]));
                    examResultList.add(examResult);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return examResultList;
    }
    
    /**
     * 检测用户名
     */
    private static String checkUserId() {
        String user = null;
        while (true) {
            System.out.print("请输入两个大写字母和4位数字的ID:");
            user = new Scanner(System.in).nextLine();
            if (user.matches("^[A-Z]{2}[0-9]{4}$")) {
                break;
            }
            System.out.println("用户ID输入有误,请重新输入");
        }
        return user;
    }
}



版权声明:本文为u014086799原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。