首页 > 其他分享 >软件工程导论个人项目互评

软件工程导论个人项目互评

时间:2023-09-20 13:13:29浏览次数:36  
标签:题目 nums int 导论 question 互评 软件工程 new public

本博客记录湖南大学2021级软件工程导论个人项目互评与代码分析

成员:

评价人:软件5班 高义林

项目作者:软件5班 谢宇鑫

需求:

  1. 命令行输入用户名和密码,两者之间用空格隔开(程序预设小学、初中和高中各三个账号,具体见附表),如果用户名和密码都正确,将根据账户类型显示“当前选择为XX出题”,XX为小学、初中和高中三个选项中的一个。否则提示“请输入正确的用户名、密码”,重新输入用户名、密码;
  2. 登录后,系统提示“准备生成XX数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):”,XX为小学、初中和高中三个选项中的一个,用户输入所需出的卷子的题目数量,系统默认将根据账号类型进行出题。每道题目的操作数在1-5个之间,操作数取值范围为1-100;
  3. 题目数量的有效输入范围是“10-30”(含10,30,或-1退出登录),程序根据输入的题目数量生成符合小学、初中和高中难度的题目的卷子。同一个老师的卷子中的题目不能与以前的已生成的卷子中的题目重复;
  4. 在登录状态下,如果用户需要切换类型选项,命令行输入“切换为XX”,XX为小学、初中和高中三个选项中的一个,输入项不符合要求时,程序控制台提示“请输入小学、初中和高中三个选项中的一个”;输入正确后,显示“”系统提示“准备生成XX数学题目,请输入生成题目数量”,用户输入所需出的卷子的题目数量,系统新设置的类型进行出题;
  5. 生成的题目将以“年-月-日-时-分-秒.txt”的形式保存,每个账号一个文件夹。每道题目有题号,每题之间空一行;

常见BUG:

  1. 登录缺少文字提示
  2. 切换出题类型后无法出卷;
  3. 每次登录仅能出卷一次
  4. 退出登录后无法重新登录
  5. 连续快速出卷导致多套题目写入同一个txt文件

代码架构:

共有6个实例类,1个抽象类

Main

Account

FileOperations

QuestionGenerator——{EasyMathProblemGenerator, NormalMathProblemGenerator, HardMathProblemGenerator}

代码分析:

public static void main(String[] args) {}
 public static void main(String[] args) {
    BufferedWriter bw;
    try {
        bw = new BufferedWriter(new FileWriter("./Account.txt"));
        bw.write(
                "张三1 123 小学\n"
                        + "张三2 123 小学\n"
                        + "张三3 123 小学\n"
                        + "李四1 123 初中\n"
                        + "李四2 123 初中\n"
                        + "李四3 123 初中\n"
                        + "王五1 123 高中\n"
                        + "王五2 123 高中\n"
                        + "王五3 123 高中");
        bw.flush();
        bw.close();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    sysCore();
}

在项目根目录下Account.txt下覆写给定的账号与对应的密码,使用try catch块包裹处理异常,之后进入sysCore方法执行登录等操作。

private static void sysCore() {}
 private static void sysCore() {
        System.out.println("欢迎登录数学试卷自动生成系统,请输入用户名,密码。输入exit退出系统。");
        if (login()) {
            System.out.println("准备生成" + currentUser.getMode() + "数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):");
            Scanner input = new Scanner(System.in);
            if (generate(input.next())) {
                sysCore();
            }
        }
    }

输出提示文字,调用login方法,如果login方法返回为真,输出登录成功后的提示文字,调用generate方法,之后递归调用本函数实现退出登录后的二次登录。

private static boolean login() {}
 private static boolean login() {
        Scanner fileWriter;
        File file = new File("./Account.txt");
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        try {
            fileWriter = new Scanner(new FileReader("./Account.txt"));
        } catch (FileNotFoundException e) {
            System.out.println("请检查文件完整性");
            return login();
        }
        Scanner input = new Scanner(System.in);
        String userName = input.next();
        if (userName.equals("exit")) {
            return false;
        }
        String userPassword = input.next();
        while (fileWriter.hasNext()) {
            String user = fileWriter.nextLine();
            String[] split = user.split(" ");
            if (split[0].equals(userName) && split[1].equals(userPassword)) {
                System.out.println("登录成功,当前选择为" + split[2] + "出题,输入‘切换为XX’更改难度(XX为小学、初中和高中三个选项中的一个)");
                currentUser.setUserName(split[0]);
                currentUser.setMode(split[2]);
                return true;
            }
        }
        System.out.println("请输入正确的用户名、密码");
        return login();
    }

从Account.txt读取的账户信息与scanner读取的输入对比实现登录,登录成功后将账号信息写入Main的静态成员currentUser并返回登录成功

如果输入为exit则返回false回到sysCore方法,如果输入不正确,递归调用login方法实现登录。存在多次登录失败导致爆栈的风险。

private static boolean generate(String order) {}
 private static boolean generate(String order) {
        if (order.length() == 5) {
            String mode = order.substring(3, 5);
            if (order.startsWith("切换为")
                    && (mode.equals("小学") || mode.equals("初中") || mode.equals("高中"))) {
                currentUser.setMode(mode);
                System.out.println("准备生成" + currentUser.getMode() + "数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):");
                Scanner in = new Scanner(System.in);
                String input = in.next();
                if (input.startsWith("切换为")) {
                    return generate(input);
                }
                return doGenerate(input);
            } else {
                System.out.println("请输入'切换为小学/初中/高中'");
                Scanner input = new Scanner(System.in);
                return generate(input.next());
            }
        } else if (order.length() < 3) {
            return doGenerate(order);
        } else {
            System.out.println("请输入正确信息");
            Scanner input = new Scanner(System.in);
            return generate(input.next());
        }
    }

在sysCore方法中登录成功后调用此方法,本方法主要实现出题模式的切换,或者在输入符合要求的数字时,将题目数量作为参数调用doGenerate方法。

递归调用本方法实现多次模式切换或出题,逻辑简明易懂。

private static boolean doGenerate(String order) {}
 private static boolean doGenerate(String order) {
        try {
            int nums = Integer.parseInt(order);
            if (Integer.parseInt(order) == -1) {
                return true;
            }
            if (10 <= nums && nums <= 30) {
                if (generateQuestions(currentUser.getMode(), nums)) {
                    System.out.println("准备生成" + currentUser.getMode() + "数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):");
                    Scanner input = new Scanner(System.in);
                    return generate(input.next());
                }
            } else {
                System.out.println("请输入10~30之间的数字");
                Scanner input = new Scanner(System.in);
                return generate(input.next());
            }
        } catch (Exception e) {
            System.out.println("请输入正确信息");
            Scanner input = new Scanner(System.in);
            return generate(input.next());
        }
        return false;
    }

该方法根据提供的参数判断调用generatQuestions方法,或是输出错误信息,之后回到generat方法

private static boolean generateQuestions(String mode, int nums) throws Exception {}
 private static boolean generateQuestions(String mode, int nums) throws Exception {
        if (10 <= nums && nums <= 30) {
            switch (mode) {
                case "小学":
                    easyMathProblemGenerator.generate(nums);
                    break;
                case "初中":
                    normalMathProblemGenerator.generate(nums);
                    break;
                case "高中":
                    hardMathProblemGenerator.generate(nums);
                    break;
            }
            return true;
        } else {
            throw new Exception();
        }
    }

该方法根据提供的参数调用对应类型的实例成员,并抛出调用过程中可能出现的异常

 

public abstract class QuestionGenerator {}
 /** 题目生成抽象类 */
public abstract class QuestionGenerator {
  /** 随机数实例 */
  public final Random r = new Random();

  /** 运算符号 */
  public final char[] operator = new char[] {'+', '-', '*', '/'};

  /**
   * 保存题目信息
   *
   * @param toSave 需要保存的题目
   */
  public void save(StringBuilder toSave) {
    LocalDateTime dateTime = LocalDateTime.now();
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss");
    try {
      FileOperations.writeQuestions(
          ".//user//"
              + Main.currentUser.getUserName()
              + "//"
              + Main.currentUser.getMode()
              + "//"
              + dateTime.format(formatter)
              + ".txt",
          String.valueOf(toSave));
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * 查重判断
   *
   * @param nums 重新生成题目数量
   * @param question 被查重题目
   * @param i 题号
   * @return 返回是否出现重复
   */
  public boolean checkQuestion(int nums, StringBuilder question, int i) {
    try {
      if (FileOperations.checkQuestions(String.valueOf(question))) {
        System.out.println("很不幸,出现了重复题目,正在为您重新生成试卷");
        this.generate(nums);
        return true;
      }
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
    question.insert(0, Integer.toString(i + 1) + '、');
    question.append("\n\n");
    return false;
  }

  /**
   * 生成题目抽象方法
   *
   * @param nums 生成数量
   */
  public abstract void generate(int nums);
}

QuestionGenerator类中定义了checkQuestion和save两个方法,分别实现查重和试卷存储的任务。将基础运算符使用静态数组存储并设为final防止重写。

QuestionGenerator抽象类中还定义了generate抽象方法,并在三个继承类中分别实现,设计了合理的代码结构,灵活应用了继承和抽象,实现了三种不同难度的出卷需求。

public class EasyMathProblemGenerator extends QuestionGenerator {}
 /** 小学题目生成 */
public class EasyMathProblemGenerator extends QuestionGenerator {
  /**
   * 实现抽象方法生成小学题目
   *
   * @param nums 生成题目数量
   */
  public void generate(int nums) {
    try {
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }
    StringBuilder question = new StringBuilder();
    for (int i = 0; i < nums; ++i) {

      int rd = r.nextInt(7) + 3;
      if (rd % 2 == 0) ++rd;
      for (int k = 0; k < rd; ++k) {
        if (k % 2 == 0) {
          question.append(r.nextInt(100) + 1);
        } else {
          question.append(operator[r.nextInt(4)]);
        }
      }
      if (checkQuestion(nums, question, i)) return;
      save(question);
      question.delete(0, question.length());
    }
    System.out.println("试卷已经生成");
  }
}
public class NormalMathProblemGenerator extends QuestionGenerator {}
 /**
 * 初中题目生成
 */
public class NormalMathProblemGenerator extends QuestionGenerator {
    /**
     * 实现抽象方法生成初中题目
     *
     * @param nums 生成题目数量
     */
    public void generate(int nums) {
        StringBuilder question = new StringBuilder();
        for (int i = 0; i < nums; ++i) {
            int rd = r.nextInt(7) + 3, sum = 0;
            if (rd % 2 == 0) ++rd;
            for (int j = 0; j < rd; ++j) {
                if (j % 2 == 0) {
                    int num = r.nextInt(100) + 1;
                    StringBuilder unit = new StringBuilder(Integer.toString(num));
                    if (j == rd - 1 && sum == 0) {
                        unit.append("^2");
                    } else {
                        if (r.nextInt(2) == 1) {
                            unit.append("^2");
                            ++sum;
                        }
                        if (r.nextInt(2) == 1) {
                            unit.insert(0, "sqrt(");
                            unit.append(")");
                            ++sum;
                        }
                    }
                    question.append(unit);
                } else {
                    question.append(operator[r.nextInt(4)]);
                }
            }
            if (checkQuestion(nums, question, i)) return;
            save(question);
            question.delete(0, question.length());
        }
        System.out.println("试卷已经生成");
    }
}
public class HardMathProblemGenerator extends QuestionGenerator {}
 /** 高中题目生成 */
public class HardMathProblemGenerator extends QuestionGenerator {
  /**
   * 实现抽象方法生成高中题目
   *
   * @param nums
   */
  public void generate(int nums) {
    StringBuilder question = new StringBuilder(), toSave = new StringBuilder();
    for (int i = 0; i < nums; ++i) {
      int rd = r.nextInt(7) + 3, sum = 0;
      if (rd % 2 == 0) ++rd;
      for (int j = 0; j < rd; ++j) {
        if (j % 2 == 0) {
          int num = r.nextInt(100) + 1;
          StringBuilder unit = new StringBuilder(Integer.toString(num));
          if (j == rd - 1 && sum == 0) {
            unit.insert(0, "sin(");
            unit.append(")");
          } else {
            if (r.nextInt(3) == 0) {
              unit.insert(0, "sin(");
              unit.append(")");
              ++sum;
            }
            if (r.nextInt(3) == 1) {
              unit.insert(0, "cos(");
              unit.append(")");
              ++sum;
            }
            if (r.nextInt(3) == 2) {
              unit.insert(0, "tan(");
              unit.append(")");
              ++sum;
            }
          }
          question.append(unit);
        } else {
          question.append(operator[r.nextInt(4)]);
        }
      }
      if (checkQuestion(nums, question, i)) return;
      save(question);
      question.delete(0, question.length());
    }
    System.out.println("试卷已经生成");
  }
}

在小学试卷出卷部分中,为了防止快速出卷导致的多张卷子写入同一txt文件,谢宇鑫同学独创性的添加了1秒的线程延迟,有效解决了这一问题,但是由于急于提交,这一修改并没有应用到初中和高中难度的出卷部分中。

在特殊运算符的添加过程中,他采用随机数判断是否添加运算符,为避免出现小概率的题目不符合要求,设置了特殊条件判断,当该题直到最后一位仍没有出现过特殊运算符,直接为最后一位添加固定的运算符。这也不失为一种巧妙的解决方式。

测试:

  

  经过初步测试没有发现bug,能够正常处理用户名、密码前、中、后的多余空格,能够正常切换试题难度,能够多次出卷,能够出题后再次切换且不报错

  理论上因为递归调用可能存在爆栈风险,但是谢宇鑫同学多数采用尾递归方式,有效规避了这一风险,值得学习。

总结:

  谢宇鑫同学的代码可读性有所欠缺,但是注释非常完备弥补了这一缺点。

  灵活运用了抽象和继承,代码复用程度高。

  合理利用private、static、final关键字,封装完善,减少了越权调用。

  题目查重部分非常完备,考虑到了多种情况。

  明文保存登陆账号、密码存在被篡改危险,有待改善。

标签:题目,nums,int,导论,question,互评,软件工程,new,public
From: https://www.cnblogs.com/scarletMoon/p/17717051.html

相关文章

  • 【HNU个人项目互评】--java
    湖南大学软件工程个人项目互评评测者:李姝萱项目作者:张乐盈 一.基本信息:  1.被评队友满足了个人项目要求的所有需求  1.1.登录:只有规定的账户可以登陆,其他的输入不会因为异常抛出强制终止程序 输入不满足格式要求,不会越界异常错误账户不能登陆登陆成功,清晰......
  • 中小学数学卷子自动生成程序——结对编程队友互评
    结对编程队友互评代码:软件2105何志成评价:软件2105陈相彤一、题目介绍用户:小学、初中和高中数学老师。功能:1、命令行输入用户名和密码,两者之间用空格隔开(程序预设小学、初中和高中各三个账号,具体见附表),如果用户名和密码都正确,将根据账户类型显示“当前选择为XX出题”,XX为......
  • HNU个人项目互评博客
    HNU个人项目——中小学数学卷子自动生成程序一.前言本次个人项目中我的搭档袁秀广同学使用了Java进行开发。袁秀广同学的代码实现了自动生成题目的基本功能,注解详细,内容丰富,但在一些细节上也存在一些可优化的地方。二.需求分析1、命令行输入用户名和密码,两者之间用空格隔开(程......
  • 【结对编程互评-C++】中小学数学卷子自动生成程序
    【结对编程互评-C++】中小学数学卷子自动生成程序项目名称:中小学数学卷子自动生成程序编程语言:C++代码作者:李义评价人:张恒硕目录[1.项目要求][1.1目标用户][1.2实现功能][2.代码分析][3.功能测试][3.1登录功能测试][3.2出题功能测试][4.优缺点分析与总结]......
  • 个人项目互评
    结队编程,分析结队队友的代码能够让小组队员之间更加了解彼此的风格。指出队友的优缺点,既能两个人互相提醒改进,也可以在往后的结队编程项目达到更好的效果。后续我将分析队友方缘的C++代码的功能及性能。基本功能实现基本要求:用户:小学、初中和高中数学老师。功能:1、命令行输......
  • 个人项目互评-中小学数学试卷生成
    个人项目互评-中小学数学试卷生成队友:软件2104李锦华队友语言选择:Python题目要求个人项目:中小学数学卷子自动生成程序用户:小学、初中和高中数学老师。功能:1、命令行输入用户名和密码,两者之间用空格隔开(程序预设小学、初中和高中各三个账号,具体见附表),如果用户名和密码都正......
  • 2023 软件工程
    Springclound的学习路线前言SpringCloud是一系列框架的有序集合,它利用SpringBoot的开发便利性简化了分布式系统的开发,比如服务发现、服务网关、服务路由、链路追踪等。SpringCloud并不重复造轮子,而是将市面上开发得比较好的模块集成进去,进行封装,从而减少了各模块的开......
  • 结对项目队友个人项目互评
    一、概述1.项目名称:中小学数学卷子自动生成程序2.编程语言:Python3.目标:分析结对编程队友的个人项目代码,分析其代码的优缺点 二、整体架构1.代码整体基于面向对象的思想,根据功能分为了数量相对较多的类,其类图如下:  根据类图可以总结其思路为:Account作为账户类......
  • HNU个人项目互评——中小学数学卷子自动生成程序
    HNU个人项目互评——中小学数学卷子自动生成程序代码作者:刘蕴哲评价人:李锦华一、个人项目需求1.用户小学、初中和高中数学老师。2.功能(1)命令行输入用户名和密码,两者之间用空格隔开(程序预设小学、初中和高中各三个账号,具体见附表),如果用户名和密码都正确,将根据账户类型显......
  • 中小学数学卷子自动生成程序-个人项目互评
    前言:首先,很有幸能有这样一次和队友互相学习的机会。正好我们两个人都是选择的C++,通过对比分析对方的代码,学习到了很多,也深刻认识到了自己的不足,还有很长的路要走。程序结构:队友的代码用了一个cpp文件便包含了所有代码,这稍微有点不好,如果能够将各个功能函数各自放在头文件,就能让......