结对项目

| 这个作业属于哪个课程 | 软件工程 |
| ---- | :----: | :----: |
| 这个作业要求在哪里 | 作业要求 |
| 这个作业的目标 | 四则运算生成器+合作完成项目 |

代码链接

结对项目

合作者

  • 姓名:李俊贤 学号:3118005367
  • 姓名:李林飞 学号:3118005368

代码链接

Github链接

PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 30 40
· Estimate · 估计这个任务需要多少时间 40 40
Development 开发 300 320
· Analysis · 需求分析 (包括学习新技术) 30 40
· Design Spec · 生成设计文档 60 80
· Design Review · 设计复审 20 30
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 40 30
· Design · 具体设计 30 30
· Coding · 具体编码 200 220
· Code Review · 代码复审 30 20
· Test · 测试(自我测试,修改代码,提交修改) 30 30
·Reporting 报告 60 60
· Test Repor · 测试报告 30 30
· 合计 850 970

项目结构

-bean
      --Exercise 单个练习题对象
-constant
      --CommandConstant 命令行参数常量
      --OperatorConstant 运算符参数常量
-exception
      --MyExpection 自定义异常 用于处理异常信息
-service
      --impl
            ---ExercisesGenerateServiceImpl 四则运算题目生成器
      ExercisesGenerateService ExercisesGenerateServiceImpl的接口
-test
      --Test 测试用例
-utils 工具类
      --CalculateUtil  用于处理计算的工具类,提供针对整数或分数的运算
      --CommobUtil 用于处理随机数的工具类,生成随机整数或随即分数
   

主要功能模块
ExercisesGenerateServiceImpl
-List<Exercise> getExerciseList(int exercisesNum, int range) 根据题目数量和数字范围生成多个题目
-String getEqualFormatQuestion(String exercise) 生成题目最简式 用于查重
-Exercise generateOneExercise(int range) 生成单条题目 用于1
-void exercisesToFile(List<Exercise> exerciseList) 将题目和答案输出到文件
-boolean checkQuestion(Exercise exercise,Set<String> questionSet) 查重
-String getAnswer(Exercise exercise) 获取题目答案
-String generateExerciseStr(Exercise exercise) 获取题目符合格式的输出
CalculateUtil
-String generateNaturalNumber(int range) 根据范围生成自然数
-String generateFraction(int range) 根据范围生成分数
-String About(String operand) 对假分数和真分数约分
-String BinocularOperation 双目运算

1.1 函数随机生成题目表达式代码
- 主要思路:根据范围随机生成一条练习题,首先随机生成运算数和运算符,设置到Exercise对象的属性容器中,调用generateExerciseStr(Exercise exercise)方法生成符合题目格式的输出
其中获取符合题目输出的算法是将所有运算数加入队列,根据运算符数量,在队列取出两个运算数与运算符生成一个表达式放入队列,直到队列只剩一个载体时,该载体就是本题题目符合
格式的输出。

      

    /**
     * 生成范围内的一条题目
     * @param range
     * @return
     */
    public Exercise generateOneExercise(int range) {
        Exercise exercise = new Exercise();
        exercise.setNumberRange(range);
        exercise.setOperatorNum(CommonUtil.getRandomNum(1,3));
        List<String> operatorList = new ArrayList<String>();
        String operator = null;
        for (int i = 0; i < exercise.getOperatorNum() ; i++) {
            operator = OperatorConstant.operatorMap.get((Integer) CommonUtil.getRandomNum(1, 4));
            operatorList.add(operator);
        }
        List<String> numList = new ArrayList<String>();
        int flag = 0;
        for (int i = 0; i < operatorList.size()+1 ; i++) {
            flag = CommonUtil.getRandomNum(0,1);
            if(flag == 0){
                numList.add(CalculateUtil.generateFraction(range));
            }else {
                numList.add(CalculateUtil.generateNaturalNumber(range));
            }
        }
        exercise.setNumbers((ArrayList<String>) numList);
        exercise.setOperators((ArrayList<String>) operatorList);
        exercise.setExerciseString(generateExerciseStr(exercise));
        exercise.setAnswer(getAnswer(exercise));
        return exercise;
    }

     /**
     * 根据Exercise对象获取符合题目格式的输出
     * @param exercise
     * @return
     */
    private static String generateExerciseStr(Exercise exercise) {
        Queue<String> queue = new LinkedList<>();
        ArrayList<String> operators = exercise.getOperators();
        ArrayList<String> numbers = exercise.getNumbers();
        for (int i = 0; i < numbers.size() ; i++) {
            queue.add(numbers.get(i));
        }
        String exerciseStr = "";
        for (int i = 0; i < operators.size() ; i++) {
            String operator = operators.get(i);
            String num1 = queue.remove();
            String num2 = queue.remove();
            if(i != operators.size()-1){
                exerciseStr = OperatorConstant.LEFT_BRACKETS+num1+operator+num2+OperatorConstant.RIGHT_BRACKETS;
            }else {
                exerciseStr = num1+operator+num2;
            }
            queue.add(exerciseStr);
        }
        StringBuilder sb = new StringBuilder("").append(queue.remove()).append("=");
        return sb.toString();
    }  

            

1.2 对题目进行检测是否符合要求和查重
- 要求是否符合思路:当答案小于0零时return false 说明题目不符合要求
- 查重:生成题目最简式,将最简式逆转,两者皆放入set集合,每次生成题目比对Set里面的值,如果存在,则排除该题目


    /**
     * 检查问题是否重复或答案是否小于0
     * @param exercise
     * @param questionSet
     * @return
     */
    public boolean checkQuestion(Exercise exercise,Set<String> questionSet){
        if(exercise == null || questionSet == null){
            throw new MyException("checkQuestion方法参数出现问题");
        }

        if(exercise.getAnswer().contains("-")){
            return false;
        }
        if(questionSet.contains(getFormatQuestion(exercise))){
            return false;
        }
        return true;
    }     

性能分析

在 -r 10000 -n 10下测试性能

可见主要性能消耗在getFormatQuestion(exercise)生成符合格式的练习题、generateOneExercise(int range)根据范围生成练习题、checkQuestion(exercise)检测题目是否符合要求和重复

上图可见主要消耗在字符串的处理上

优化思路:查重构建练习题答案的Set容器,将答案放入Set容器中,将练习题当答案重复时,取出这一题目,重新生成。

测试


运行结果

Exercises.txt

Answer.txt

单元测试

利用Junit进行单元测试

序号 样例
1 -n 1 -r 1
2 -n 1 -r 10
3 -n 1 -r 100
4 -n 10 -r 1
5 -n 100 -r 1
6 -n 100 -r 10
7 -n 100 -r 100
8 -n 1000 -r 10
9 -n 10000 -r 10
10 -n 10000 -r 100
部分测试代码
    //10000,10
    @Test
    public void testMethod09() throws IOException {
        ExercisesGenerateService service = new ExercisesGenerateServiceImpl();
        service.exercisesToFile(service.getExerciseList(10000,10));
    }

    //10000,100
    @Test
    public void testMethod10() throws IOException {
        ExercisesGenerateService service = new ExercisesGenerateServiceImpl();
        service.exercisesToFile(service.getExerciseList(10000,100));
    }

项目小结

李俊贤:结对编程需要很好的沟通,提前设计好接口,做好需求分析,安排参数非常重要,做好模块设计。
李林飞:需求分析很重要,设计文档要写好。

posted @ 2020-10-13 00:32  DDDDARK  阅读(128)  评论(0)    收藏  举报