项目需求

  小学、初中和高中数学老师用户自动生成试卷

  要完成的功能有:

  • 命令行输入用户名和密码进行登录
  • 登录成功显示用户可生成的题目类型,可以输入所需的题目数量(要求数量在10-30之间)
  • 生成的题目保存到目标用户名文件中并以"年-月-日-时-分-秒.txt"的形式保存,每个用户名一个文件夹,题目开头有序号并且每题之间要空一行,同一账号生成的题目不允许和已生成的题目重复。
  • 登录状态下,可切换老师类型
  • 输入-1,可退出登录

代码分析

  结构简单明了,仅使用三个类,命名符合规范,让人很容易就能知道每个类的作用。

User.java 用于存储用户数据结构,私有成员,安全性不错。

GeneratePaper.java

使用相对路径读取,生成题目,迁移方便。
三个成员函数,setProblem生成单道题,pastProblem遍历历史题目存在哈希表里。makepaper调用前面两个函数生成试卷。

Ui.java

用于用户交互,主函数调用其他类完成程序需求。
在迭代时可以用于修改,实现后端接口,拓展性好。

代码优缺点具体分析

优点

1. 检查题目是否重复使用哈希表,保证了程序性能

对于海量数据中的精确查找有非常惊人的速度提升,理论上即使有无限的数据量,一个实现良好的哈希表依旧可以保持O(1)的查找速度,而O(n)的普通列表此时已经无法正常执行查找操作(实际上不可能,受到JVM可用内存限制,机器内存限制等)。

具体代码如下:
public HashSet<String> pastProblem(File file){
       HashSet<String> pastProblem= new HashSet<String>();
       File[] all = file.listFiles();//all文件数组,读取用户夹
       for (File file1:all){
           if (!file1.isDirectory()){//非目录则读取
               try {
                   BufferedReader reader = new BufferedReader(new FileReader(file1));
                   String temp = reader.readLine();
                   while(temp !=null){//读取到的题目存于哈希表
                       String[] cur=null;
                       if (temp.length()>2) {//将题目去题号
                           cur = temp.split("\\.");
                           pastProblem.add(cur[1]);
                       }
                       temp = reader.readLine();
                   }
                   reader.close();
               }catch (Exception e){
                   e.printStackTrace();
               }
           }
       }
        return pastProblem;
    }

2. 题目生成思路非常好,代码复用性高

先上代码,再来解说

//生成单个题目
    public String setProblem(String type){
        Random rand = new Random();//随机
        String[] symbol = {"+", "-", "*", "/"};//共用普通字符表
        int size = 0;//题目的操作数
        String[] data = null;//题目中的数字
        if (type.equals("小学")){
            size = rand.nextInt(4)+2;//生成2-5个操作数
            data = new String[size];
            for (int i = 0; i<size; i++){
                data[i]=String.valueOf(rand.nextInt(100)+1);
            }
        }
        else if (type.equals("初中")) {
            size = rand.nextInt(5) + 1;//生成1-5个操作数
            data = new String[size];
            boolean[] flag = new boolean[size];
            int specialSymbol = rand.nextInt(size) + 1;//至少1个平方运算
            for (int i = 0; i < size; i++) {
                data[i] = String.valueOf(rand.nextInt(100) + 1);
            }
            for (int i = 0; i < specialSymbol; i++) {//添加初中特有字符
                int index = rand.nextInt(size);
                if (!flag[index]) {
                    if (rand.nextInt(2) == 0 ) {
                        data[index] = "√" + data[index];
                    } else {
                        data[index] = data[index] + "²";
                    }
                    flag[index] = true;
                }
            }
        }
        else if (type.equals("高中")) {
            size = rand.nextInt(5) + 1;
            data = new String[size];
            boolean[] flag = new boolean[size];
            int specialSymbol1 = rand.nextInt(size) + 1;//至少1个角运算
            int specialSymbol2 = rand.nextInt(size) + 1;//至少1个角运算
            for (int i = 0; i < size; i++) {
                data[i] = String.valueOf(rand.nextInt(100) + 1);
            }
            for (int i = 0; i < specialSymbol1; i++) {//添加角运算
                int index = rand.nextInt(size);
                if (!flag[index]) {
                    switch (rand.nextInt(3)){
                        case 0:
                            data[index] = "sin" + data[index];
                            break;
                        case 1:
                            data[index] = "cos" + data[index];
                            break;
                        case 2:
                            data[index] = "tan" + data[index];
                            break;
                    }
                    flag[index] = true;
                }
            }
            for (int i = 0; i < specialSymbol2; i++) {//添加初中已学的运算
                int index = rand.nextInt(size);
                if (!flag[index]) {
                    if (rand.nextInt(2) == 0 ) {
                        data[index] = "√" + data[index];
                    } else {
                        data[index] = data[index] + "²";
                    }
                    flag[index] = true;
                }
            }


        }
        else {
            System.out.println("非标准输入,创建有误");
        }

        //随机加上括号
        if (size >= 3 && rand.nextInt(2) == 0) {
            int gap = rand.nextInt(size - 2) + 1;
            int left = rand.nextInt(size - gap);
            int right = left + gap;
            data[left] = "(" + data[left];
            data[right] = data[right] + ")";
        }

        //将数字以符号连接生成题目
        String problem = " ";
        if (data!=null) {
            problem = data[0];
            for (int i = 0; i < size - 1; i++) {
                problem += symbol[rand.nextInt(4)];//随机添加基础字符
                problem += data[i + 1];
            }
            problem += "=";
        }
        return problem;
    }

三种试卷类型公用的符号放于通用字符数组。采用数值与符号分离的方法来生成题目。三个类型都是先生成随机的操作数和具体数值,然后在数值之间以随机的通用符号连接。对于初高中的特有字符,对方没有采用与普通字符一样的处理手段,而是选择与数值绑定,存于数值所在的string数组中。另外在最后,加上括号。代码简单,逻辑清晰,实为上佳之作。

缺点

1. 导入文件不符合规范,出现通配符*

2. 一次输出信息较多,但没有对文字内容进行如加边框或居中等美化处理

3. 账号采用文本文件存储,未使用数据库,该方面可做拓展提升

总结

队友代码可读性和可维护性还是不错的,也有使用静态方法,可以直接被主函数调用,节省空间提高了效率。小问题也是有的,希望能就代码规范进行再次学习。本次我们两人选择的代码语言并不一样,在互相看代码的过程中,触发了新的思路,新的想法,同时也收获很多,期待结对项目的合作。