结对项目

这个作业属于哪个课程 <23级软件工程>
这个作业要求在哪里 <作业要求的链接>
这个作业的目标 学习PSP2.1思想下的程序设计实现方法,学习程序设计中的团队合作
开发者 庄楷彬(3123004250),覃锴锋(3123004240)

作业文件链接

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 15 10
· Estimate · 估计这个任务需要多少时间 15 10
Development 开发 650 565
· Analysis · 需求分析 (包括学习新技术) 180 150
· Design Spec · 生成设计文档 30 15
· Design Review · 设计复审 10 5
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 10 5
· Design · 具体设计 30 20
· Coding · 具体编码 150 140
· Code Review · 代码复审 60 35
· Test · 测试(自我测试,修改代码,提交修改) 180 195
Reporting 报告 100 90
· Test Repor · 测试报告 60 65
· Size Measurement · 计算工作量 10 5
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 30 20
合计 765 665

程序总体设计

需求分析

1. 概述

本次作业要求编写一个生成小学四则运算题目的命令行工具,同时具备答案生成与检查功能。

2.程序总体功能划分

程序具体设计

程序各接口设计与实现

模块总体设计

1.主模块

  • 读取输入的命令行参数(-n, -r, -e, -a)。
  • 功能
    • 验证 -n-e是否存在,否则报错。
    • 区分生成模式(-n)或检查模式(-e-a
    • 在生成模式下验证 -r 是否存在,否则报错。

2.带分数模块

功能:
  • 实现带分数存储与计算
  • 进行单个带分数的随机生成

3.方程模块

  • 记录方程的各个元素
  • 计算方程的解

4.问题生成模块

功能:
  • 生成运算符不超过3个的表达式。
  • 确保计算过程不产生负数,除法结果为真分数。
  • 避免重复题目。

5.文件写入模块

功能:

将题目数据写入到文件中。

模块具体设计

各模块具体接口如下:

  1. 主模块

    public static void main(String[] args)
    
  2. 带分数模块

    带分数的类定义如下:

    class MixedNumber {
        int interger;//带分数的整数部分
        int numerator;//带分数的分子部分
        int denominator;//带分数的分母部分
    }
    

    带分数模块有以下函数:

    • MixedNumber()//构造函数,生成值为0,分母为1的标准带分数
      
    • void setValue(MixedNumber M)//将M的值赋值给此带分数
      
    • int isEqual(MixedNumber num)//判断两待分数是否相等
      
    • int isNegative()//判断此带分数是否为正数
      
    • private int gcd(int a,int b)//寻找最大公约数
      
    • private void simplify()//化简带分数
      
    • void randomNumber(int r)//生成随机带分数
      
    • MixedNumber negation()//将数转换为负数,用于减法
      
    • MixedNumber mixNumberMultiply(MixedNumber numA,MixedNumber numB)//带分数乘法
      
    • MixedNumber mixNumberAdd(MixedNumber numA,MixedNumber numB)//带分数加法
      
    • MixedNumber mixNumberDivide(MixedNumber numA,MixedNumber numB)//带分数除法
      
    • String getNumber()//将带分数转换为字符串形式输出
      
  3. 方程模块

方程的类定义如下:

public class Question {
    MixedNumber[] elements;
    int[] operator;
    MixedNumber result;
}

方程模块有以下函数:

  • Question()//构造函数,生成空方程
    
  • void copyQuestion(Question Q)//将方程Q赋值给次方程
    
  • MixedNumber getAnswerCalc()//解析方程,给出计算顺序
    
  • MixedNumber getAnswer(int t)//进行单次计算
    
  • String getdataString()//将方程作为字符串输出
    
  • String getAnswerString()//将答案以字符串的形式输出
    

4.方程生成模块

方程生成模块的类定义如下:

public class QuestionGenerator {
    int n;//生成题目数量
    int r;//生成范围
    List<Question> questions = new ArrayList<>();//方程链表
}

有以下函数:

  • public void questionGenerate()//方程生成函数
    
  • QuestionGenerator(int n,int r)//构造函数
    

5.文件写入模块

文件写入模块的类定义如下:

public class writeFile {
    static String[] fileName = {"Exercises.txt","Answers.txt"};
}

有以下函数:

public static void writeExerciseFile(QuestionGenerator generator)//写入方程

性能改进

程序性能消耗最大的函数为方程生成函数

public void questionGenerate(){
        int t1,t2,t3=0;
        Random random=new Random();
        Question tmpQuestion = new Question();
        for(t1=0;t1<this.n;t1++){
            Question question=new Question();
            question.elements[0].randomNumber(r);
            question.operator[0] = random.nextInt(4)+1;//第一个运算符号不能为等于号
            question.elements[1].randomNumber(r);
            question.operator[1] = random.nextInt(5);
            if(question.operator[1] != 0){//如果第二个运算符号为等于号,则不必继续生成
                question.elements[2].randomNumber(r);
                question.operator[2] = 0;
                if(random.nextInt(10)-5>0){
                    question.operator[1] += 10;
                }
                //十分之一的概率生成括号
            }
            tmpQuestion.copyQuestion(question);
            try{
                question.result.setValue(tmpQuestion.getAnswerCalc());
            } catch (NullPointerException e) {
                t1--;
                continue;
            }
            for(t2=0;t2<questions.size();t2++){//查重逻辑如下:首先判断结果是否相等,其次检查各元素是否相等
                if(question.result.isEqual(questions.get(t2).result)==0){
                    continue;
                }
                for(t3=0;t3 < question.elements.length-1; t3++){
                    if(questions.get(t2).elements[t3].isEqual(question.elements[t3]) == 0){
                        break;
                    }
                }
                if(questions.get(t2).elements[t3].isEqual(question.elements[t3]) == 0){
                    t3 = question.elements.length+1;
                    break;
                }
            }
            if(t3 == question.elements.length+1){//如果发现重复,则丢弃此次生成式子重新生成
                t1--;
                continue;
            }
            questions.add(question);
        }
    }
}

这里通过减少不必要的步骤来提高效率。

程序测试

单元测试展示

单元测试

1.测试正常输入

@Test
void Test01(){
    String[] args={"-n","10","-r","10"};
    Main.main(args);
}

2.测试单输入变量下的情况

@Test
//测试单输入变量下的情况
void Test02(){
    String[] args={"-n","10"};
    Main.main(args);
}
@Test
void Test03(){
    String[] args={"-r","10"};
    Main.main(args);
}
@Test
void Test04(){
    String[] args={"-e","10"};
    Main.main(args);
}
@Test
void Test05(){
    String[] args={"-a","10"};
    Main.main(args);
}

3.测试检测功能

@Test
void Test06(){
    String[] args={"-e","Exercises.txt","-a","Answers.txt"};
    Main.main(args);
}

4.测试检测功能输入异常报错

@Test
void Test07(){
    String[] args={"-e","Areyousure?","-a","I'm_not_a.txt"};
    Main.main(args);
}

5.测试10000题输出

@Test
void Test08(){
    String[] args={"-n","10000","-r","10"};

    assertTimeout(Duration.ofSeconds(100),() -> {
        Main.main(args);
    });
}

6.测试大数输出

void Test09(){
    String[] args={"-n","10","-r","10000"};

    assertTimeout(Duration.ofSeconds(100),() -> {
        Main.main(args);
    });
}

7.测试两项功能同时激活

void Test10(){
    String[] args={"-e","Areyousure?","-a","I'm_not_a.txt","-n","10","-r","10"};
    Main.main(args);
}

异常处理

1.在读取文件时没有发现相应文件:

处理方法如下:

try {
                    new GradeExercises().gradeExercises(args[i + 1], args[i + 3]);
                } catch (IOException e) {
                    System.out.println("Error grading exercises: " + e.getMessage());
                }

测试单元见test07

2.在输入时输入了-n但没有输入-r

处理方法如下:

if(r == 0){
                System.out.println("程序检测到输入-n但没有指定-r的值,请确认您的输入是否正确");
            }

测试单元见test02

3.写入文件时写入失败

处理方法如下:

try {
    BufferedWriter out = new BufferedWriter(new FileWriter(fileName[1]));
    int t;
    for(t = 0;t < generator.questions.size(); t++ ){
        out.write(t+1+". "+generator.questions.get(t).getAnswerString()+"\n");
    }
    out.close();
} catch (IOException e) {
    System.out.println("写入出现错误,请检查硬盘空间是否充足及程序是否有足够的权限");
}

小结

在本次作业中,我收获良多。

😂由于JAVA好久没写了,这次几乎是从头开始从新学了一遍。

非常感谢这次和我合作的同伴覃锴锋,在这次程序设计中给了我很大的帮助。在我因为太久没写java而产生了许多bug时,他耐心而又热情地帮我指出了这些错误。同时他也很好地完成了他负责的方程检验部分。

posted @ 2025-03-22 20:44  听风的雨  阅读(30)  评论(0)    收藏  举报