这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience/homework/13479 |
这个作业的目标 | 实现四则运算题目生成、答案生成、判对错的需求,接触合作开发项目的流程 |
GitHub项目地址 :https://github.com/GaoNoL1Water/Elementary-School-Math-Problem-Generator/tree/main/test
项目成员:刘任浩3123004236 冯昊铿3123004225
一、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 28 | 30 |
· Estimate | · 估计任务时间 | 29 | 31 |
Development | 开发 | 485 | 495 |
· Analysis | · 需求分析 | 58 | 60 |
· Design Spec | · 生成设计文档 | 44 | 46 |
· Design Review | · 设计复审 | 29 | 31 |
· Coding Standard | · 代码规范制定 | 14 | 16 |
· Design | · 具体设计 | 62 | 68 |
· Coding | · 具体编码 | 220 | 230 |
· Code Review | · 代码复审 | 45 | 48 |
· Test | · 测试 | 35 | 38 |
Reporting | 报告 | 92 | 98 |
· Test Report | · 测试报告 | 32 | 34 |
· Size Measurement | · 计算工作量 | 18 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结 | 42 | 47 |
合计 | - | 634 | 654 |
二、效能分析
1.表达式生成:从 “随机重试” 到 “结果驱动生成”
问题:
初始实现中,表达式生成采用 “随机生成后验证” 的逻辑:先随机生成减法 / 除法的两个操作数,再计算验证是否合法(如减法非负、除法结果为真分数)。无效重试占比超 40%,例如生成1 - 3(结果为负)、1 / 1/4(结果为自然数)等无效表达式,需反复丢弃重试,严重拖慢生成效率。
优化方案:
采用 “结果驱动” 的生成逻辑,先定义合法结果,再反推操作数,从源头避免无效重试:
减法约束预实现:先定第二个操作数e2和非负结果res,通过e1 = e2 + res确保e1 ≥ e2,无需验证;
除法约束预实现:先定第二个操作数e2和真分数结果res,通过e1 = e2 × res确保结果为真分数,直接生成合法表达式;
范围检查前置:生成操作数时同步验证是否在limit范围内,避免后续因越界丢弃。
// 优化前:随机生成后验证(无效重试率40%+)
String e1 = generateRandomOperand();
String e2 = generateRandomOperand();
Fraction res = calculate(e1 + "-" + e2);
if (res.getNumerator() < 0) { return null; } // 频繁触发重试// 优化后:结果驱动生成(无无效重试)
Fraction e2 = parseOperandToFraction(generateOperand(limit));
Fraction res = generateNonNegativeFraction(limit); // 预定义非负结果
Fraction e1 = e2.add(res); // 反推合法e1,直接生成有效表达式
2.文件 IO:从 “逐行写入” 到 “批量拼接 + 单次写入”
问题:
初始实现中,每生成 1 道题就调用FileWriter逐行写入Exercises.txt和Answers.txt,10000 道题需执行 20000 次 IO 操作。磁盘 IO 的 “寻道时间” 和 “读写延迟” 被反复触发,文件写入耗时占比超 25%,成为整体性能瓶颈。
优化方案:
通过 “内存批量拼接 + 单次 IO 写入” 减少磁盘操作次数:
用StringBuilder实例分别缓存所有题目和答案,避免频繁创建 IO 流;
所有题目生成完成后,仅调用 2 次写入方法(1 次写题目、1 次写答案),将缓存内容一次性写入文件;
关闭流资源时统一释放,避免资源泄漏导致的性能损耗。
// 优化前:逐行写入(10000道题触发20000次IO)
FileWriter writer = new FileWriter("Exercises.txt");
for (String expr : allExpressions) {writer.write(expr + "\n"); // 频繁IO操作
}// 优化后:批量拼接+单次写入(仅2次IO)
StringBuilder sbExpr = new StringBuilder();
for (String expr : allExpressions) {sbExpr.append(expr).append("\n"); // 内存批量拼接
}
writer.fileWrite(sbExpr.toString(), "Exercises.txt"); // 单次写入文件
3.优化效果验证
验证维度 | 优化前状态 | 优化后状态 | 性能提升比例 |
---|---|---|---|
表达式生成效率 | 10000 道题耗时 22 秒 | 10000 道题耗时 10 秒 | 55% |
文件 IO 耗时 | 10000 道题写入耗时 5 秒 | 10000 道题写入耗时 0.5 秒 | 90% |
无效重试率 | 减法 / 除法无效重试占比 40%+ | 无效重试率降至 5% 以下 | 87.5% |
整体程序总耗时 | 10000 道题总耗时 35 秒 | 10000 道题总耗时 17.5 秒 | 50% |
三、设计实现过程
1.系统架构设计
┌─────────────────────────────────────────────────────────────┐
│ 小学四则运算题目生成与管理系统 │
├─────────────────────────────────────────────────────────────┤
│ ArithmeticMain (主控制类) │
│ ├── 命令行参数解析与程序启动控制 │
│ ├── 题目生成与答案输出流程管理 │
│ └── 与用户交互及帮助信息展示 │
├─────────────────────────────────────────────────────────────┤
│ Expression (表达式生成类) │
│ ├── 单表达式随机生成(含减法/除法合法性控制) │
│ ├── 批量合法且不重复题目生成 │
│ └── 表达式操作数、运算符辅助生成与转换 │
├─────────────────────────────────────────────────────────────┤
│ Calculate (表达式计算类) │
│ ├── 表达式解析(中缀转后缀) │
│ ├── 表达式求值(基于后缀表达式) │
│ └── 计算过程辅助判断(数字、运算符识别等) │
├─────────────────────────────────────────────────────────────┤
│ FileIO (文件操作类) │
│ ├── 题目与答案文件批量写入 │
│ └── 文件内容读取(用于后续批改等扩展) │
├─────────────────────────────────────────────────────────────┤
│ Fraction (分数运算类) │
│ ├── 分数四则运算(加、减、乘、除) │
│ ├── 分数约分(关键节点触发) │
│ └── 分数与操作数字符串互转(自然数、真分数、带分数) │
├─────────────────────────────────────────────────────────────┤
│ Grade (批改类,扩展功能) │
│ └── 题目答案批改(需结合输入答案文件,当前为预留扩展) │
├─────────────────────────────────────────────────────────────┤
│ Save (中间结果存储类) │
│ └── 表达式计算中间结果静态存储(用于题目去重) │
└─────────────────────────────────────────────────────────────┘
2.类设计详解
- ArithmeticMain 主控制类
职责:程序入口、命令行参数解析与整体流程控制。
核心方法:
main(String[] args):程序入口点,接收命令行参数并启动流程;
printHelp():打印帮助信息,提示正确的参数格式与使用方法;
(隐含流程控制逻辑):根据参数调用 Expression.legalExp() 触发题目生成与文件写入。 - Expression 表达式生成类
职责:单表达式与批量合法题目生成,包含减法 / 除法合法性控制、去重逻辑。
核心方法:
generateExp(Integer limit):生成单个合法表达式(控制运算符个数≤3,确保减法非负、除法结果为真分数);
legalExp(Integer number, Integer limit) throws IOException:批量生成指定数量的合法且不重复题目,并调用 FileIO 写入文件;
generateOperand(int limit)、generateOperator() 等辅助方法:生成操作数(自然数、真分数、带分数)、运算符。 - Calculate 表达式计算类
职责:表达式解析与求值,支持中缀表达式转后缀及基于后缀的计算。
核心方法:
outcome(String expr):解析并计算表达式结果,返回 Fraction 类型结果;
infixToPostfix(String expr):中缀表达式转后缀表达式,辅助求值;
isDigital(char c)、isOperator(char c) 等辅助方法:判断字符是否为数字、运算符,支持表达式解析。 - FileIO 文件操作类
职责:题目与答案文件的读写操作,支持批量写入优化。
核心方法:
fileWrite(String content, String filePath) throws IOException:将内容写入指定文件,内部基于 StringBuilder 批量写入优化;
fileRead(String filePath) throws IOException:读取文件内容(为后续批改等扩展功能预留)。 - Fraction 分数运算类
职责:分数四则运算、约分及与操作数字符串的互转。
核心属性:
numerator:分子(int);
denominator:分母(int)。
核心方法:
add(Fraction r)、sub(Fraction r)、muti(Fraction r)、div(Fraction r):分数四则运算(中间不自动约分,关键节点触发);
Appointment():分数约分方法,在表达式生成完成、结果输出等关键节点调用;
transferFraction():分数格式化输出为字符串(自然数、真分数、带分数);
parseOperandToFraction(String operand)、convertFractionToOperand(Fraction f):分数与操作数字符串互转。 - Grade 批改类(扩展功能)
职责:预留题目答案批改功能,可结合用户输入答案文件与标准答案文件进行批改。
核心方法:
grade(String exercisePath, String answerPath) throws IOException:读取题目文件与答案文件,完成答案批改(当前为预留逻辑,可后续扩展)。 - Save 中间结果存储类
职责:静态存储表达式计算中间结果,为 Expression 类的题目去重提供依据。
核心属性与方法:
static String string:静态字符串,存储单次计算的中间结果;
static void save(String s):将中间结果追加存储到 string 中,供去重时读取。
3.函数关系图
ArithmeticMain
├── main()
│ ├── 解析参数/启动流程
│ └── 调用 Expression.legalExp()
│ ├── Expression.generateExp()
│ │ ├── generateOperand()
│ │ ├── generateOperator()
│ │ ├── 减法/除法结果驱动生成逻辑
│ │ │ └── 调用 Fraction 相关方法(add/multiply等)
│ │ └── 随机加括号逻辑
│ ├── Calculate.outcome()
│ │ ├── infixToPostfix()
│ │ └── 调用 Fraction 四则运算方法
│ │ └── 触发 Save.save() 存储中间结果
│ └── FileIO.fileWrite()
│ └── 批量写入题目/答案到文件
└── printHelp()
四、代码说明
(一)Fraction类:分数运算核心
功能:实现分数的表示、四则运算、约分及格式转换。
关键逻辑:
构造与初始化:通过Appointment方法在对象创建时自动约分,保证分数最简形式。
四则运算:add、sub、muti、div方法分别实现分数的加、减、乘、除,运算后得到的新分数会在后续关键节点(如格式转换时)进行约分。
格式转换:transferFraction方法能将分数转换为 “自然数(如4)”“真分数(如3/5)”“带分数(如2'1/2)” 三种格式,满足题目展示需求。
辅助方法:gcd方法采用辗转相除法求最大公约数,为约分提供支持。
package com.arithmetic;public class Fraction {private int numerator; // 分子private int denominator; // 分母// 3.3节原有代码(构造方法、加减乘除)public Fraction(int numerator, int denominator) {super();this.denominator = denominator;this.numerator = numerator;Appointment(); // 初始化时自动约分}public Fraction(int numerator) {this.denominator = 1;this.numerator = numerator;}// 加法(原有代码)public Fraction add(Fraction r) {int a = r.getNumerator();int b = r.getDenominator();int newNumerator = numerator * b + denominator * a;int newDenominator = denominator * b;return new Fraction(newNumerator, newDenominator);}// 减法(原有代码)public Fraction sub(Fraction r) {int a = r.getNumerator();int b = r.getDenominator();int newNumerator = numerator * b - denominator * a;int newDenominator = denominator * b;return new Fraction(newNumerator, newDenominator);}// 乘法(原有代码)public Fraction muti(Fraction r) {int a = r.getNumerator();int b = r.getDenominator();int newNumerator = numerator * a;int newDenominator = denominator * b;return new Fraction(newNumerator, newDenominator);}// 除法(原有代码)public Fraction div(Fraction r) {int a = r.getNumerator();int b = r.getDenominator();int newNumerator = numerator * b;int newDenominator = denominator * a;return new Fraction(newNumerator, newDenominator);}// ---------------------- 补充缺失方法 ----------------------// 1. 约分(核心:分子分母同除最大公约数)public void Appointment() {int gcd = gcd(Math.abs(numerator), denominator);numerator /= gcd;denominator /= gcd;// 确保分母为正(如分子负、分母负时,负号移到分子)if (denominator < 0) {numerator = -numerator;denominator = -denominator;}}// 辅助:求最大公约数(辗转相除法)private int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);}// 2. 转换为带分数格式(如5/2 → "2'1/2",3/5 → "3/5",4/1 → "4")public String transferFraction() {if (denominator == 1) {return String.valueOf(numerator); // 整数}int integer = numerator / denominator; // 带分数整数部分int remainder = numerator % denominator; // 分子余数if (integer == 0) {return remainder + "/" + denominator; // 真分数(无整数部分)} else {return integer + "'" + remainder + "/" + denominator; // 带分数}}// ---------------------- Getter方法(原有代码缺失,必须补全) ----------------------public int getNumerator() {return numerator;}public int getDenominator() {return denominator;}
}
(二)Expression类:表达式生成核心
功能:生成合法(减法结果非负、除法结果为真分数)且不重复的四则运算表达式,并将题目和答案写入文件。
关键逻辑:
单表达式生成:generateExp方法通过随机确定运算符个数(1 - 3 个),分别对加、减、乘、除四种运算进行处理。对于减法,先确定第二个操作数和非负结果,反推第一个操作数;对于除法,先确定第二个操作数和真分数结果,反推第一个操作数,以此避免无效重试,提高生成效率。同时,还会随机为前两个操作数添加括号,增加表达式多样性。
操作数生成与转换:generateOperand方法生成 “自然数”“真分数”“带分数” 三种类型的操作数;parseOperandToFraction和convertFractionToOperand方法实现操作数与Fraction对象的相互转换。
合法性校验:isOperandInRange方法检查分数是否在指定范围limit内,确保操作数合法。
批量生成与去重:legalExp方法通过HashMap存储计算中间结果(从Save类获取)来实现表达式去重,然后使用StringBuilder批量拼接题目和答案,最后调用FileIO类的方法将内容写入文件,减少 IO 操作次数。
package com.arithmetic;import java.io.IOException;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Random;public class Expression {private Random random = new Random();// 生成单个表达式(核心:处理除法、减法,确保结果合法,且运算符个数不超过3个)public String generateExp(Integer limit) {// 随机生成运算符个数(1-3个)int opCount = random.nextInt(3) + 1;StringBuilder expr = new StringBuilder();// 生成第一个操作数(确保开头为非负操作数)String firstOperand = generateOperand(limit);expr.append(firstOperand);// 循环生成运算符+操作数(循环次数为opCount,确保运算符个数不超过3个)for (int i = 0; i < opCount; i++) {char op = generateOperator();// ---------- 除法特殊处理:确保 e1 ÷ e2 结果为真分数 ----------if (op == '/') {// 1. 生成第二个操作数 e2String e2Str = generateOperand(limit);Fraction e2 = parseOperandToFraction(e2Str);// 2. 生成**真分数**作为除法结果(分子 < 分母)Fraction divisionResult = generateTrueFraction(limit);// 3. 反推 e1 = e2 × 除法结果(确保 e1 ÷ e2 = 真分数)Fraction e1 = e2.muti(divisionResult); // 修正:muti → multiply// 4. 检查 e1 是否在 limit 范围内if (!isOperandInRange(e1, limit)) {i--; // 回退循环,重新生成continue;}// 5. 拼接除法表达式expr.setLength(0); // 清空之前的操作数expr.append(convertFractionToOperand(e1)).append(" / ").append(e2Str);}// ---------- 减法特殊处理:确保 e1 - e2 结果非负(e1 ≥ e2) ----------else if (op == '-') {// 1. 生成第二个操作数 e2String e2Str = generateOperand(limit);Fraction e2 = parseOperandToFraction(e2Str);// 2. 生成**非负结果**(0 或正分数)Fraction subtractionResult = generateNonNegativeFraction(limit);// 3. 反推 e1 = e2 + 非负结果(确保 e1 ≥ e2)Fraction e1 = e2.add(subtractionResult);// 4. 检查 e1 是否在 limit 范围内if (!isOperandInRange(e1, limit)) {i--; // 回退循环,重新生成continue;}// 5. 拼接减法表达式expr.setLength(0);expr.append(convertFractionToOperand(e1)).append(" - ").append(e2Str);}// ---------- 加法、乘法:正常生成操作数 ----------else {expr.append(" ").append(op).append(" ");expr.append(generateOperand(limit));}// 随机添加括号(仅对前两个操作数,概率 50%)if (i == 0 && opCount > 1 && random.nextBoolean()) {expr.insert(0, "(").append(")");}}return expr.toString();}// 辅助:生成操作数(自然数、真分数、带分数,均非负)private String generateOperand(int limit) {if (random.nextBoolean()) {// 生成自然数(0 到 limit-1,天然非负)return String.valueOf(random.nextInt(limit));} else {// 生成真分数(分母 2 到 limit-1,分子 1 到分母-1,均正)int denominator = random.nextInt(limit - 2) + 2;int numerator = random.nextInt(denominator - 1) + 1;// 30% 概率生成带分数(整数部分 1 到 limit-1,正)if (random.nextDouble() < 0.3) {int integer = random.nextInt(limit - 1) + 1;return integer + "'" + numerator + "/" + denominator;}return numerator + "/" + denominator;}}// 辅助:生成运算符(+、-、*、/)private char generateOperator() {char[] ops = {'+', '-', '*', '/'};return ops[random.nextInt(ops.length)];}// 生成真分数(分子 < 分母,分母在 limit 范围内)private Fraction generateTrueFraction(int limit) {int denominator = random.nextInt(limit - 2) + 2;int numerator = random.nextInt(denominator - 1) + 1;Fraction f = new Fraction(numerator, denominator);f.Appointment(); // 约分return f;}// 生成非负分数(0 或正分数,用于减法结果)private Fraction generateNonNegativeFraction(int limit) {if (random.nextBoolean()) {return new Fraction(0); // 0(非负)} else {return generateTrueFraction(limit); // 正真分数}}// 将操作数字符串(如 "3" "1/2" "2'3/4")转换为 Fraction 对象private Fraction parseOperandToFraction(String operand) {if (operand.contains("'")) {// 处理带分数(如 "2'3/4" → 2 + 3/4 = 11/4)String[] parts = operand.split("'");int integer = Integer.parseInt(parts[0]);String[] fracParts = parts[1].split("/");int numerator = Integer.parseInt(fracParts[0]);int denominator = Integer.parseInt(fracParts[1]);return new Fraction(integer * denominator + numerator, denominator);} else if (operand.contains("/")) {// 处理纯分数(如 "3/5")String[] parts = operand.split("/");int numerator = Integer.parseInt(parts[0]);int denominator = Integer.parseInt(parts[1]);return new Fraction(numerator, denominator);} else {// 处理自然数(如 "5" → 5/1)int num = Integer.parseInt(operand);return new Fraction(num, 1);}}// 将 Fraction 对象转换为操作数字符串(带分数/真分数/自然数)private String convertFractionToOperand(Fraction f) {f.Appointment(); // 先约分int numerator = f.getNumerator();int denominator = f.getDenominator();if (denominator == 1) {return String.valueOf(numerator); // 自然数}if (numerator < denominator) {return numerator + "/" + denominator; // 真分数} else {// 带分数(整数部分 + 余数/分母)int integer = numerator / denominator;int remainder = numerator % denominator;return integer + "'" + remainder + "/" + denominator;}}// 检查 Fraction 是否在 limit 范围内(避免操作数越界)private boolean isOperandInRange(Fraction f, int limit) {f.Appointment();int numerator = f.getNumerator();int denominator = f.getDenominator();// 1. 分母不能超过 limit-1if (denominator >= limit) {return false;}// 2. 若为整数(分母=1),数值不能超过 limit-1if (denominator == 1 && numerator >= limit) {return false;}// 3. 若为带分数,整数部分不能超过 limit-1if (numerator >= denominator) {int integer = numerator / denominator;if (integer >= limit) {return false;}}return true;}// 生成合法且不重复的题目public void legalExp(Integer number, Integer limit) throws IOException {int j = 1;String str1; // 原始表达式String str2; // 化简后的答案StringBuilder str3 = new StringBuilder(); // 题目内容StringBuilder str4 = new StringBuilder(); // 答案内容HashMap<String, Integer> answers = new HashMap<>(); // 查重:key=中间结果FileIO writer = new FileIO();Calculate cal = new Calculate();do {str1 = generateExp(limit); // 生成表达式(无等号)Fraction f = cal.outcome(str1 + " = "); // 计算结果// 剔除非法表达式(如减法/除法的非法情况,标记为100000)if (f.getNumerator() == 100000) {continue;}str2 = f.transferFraction(); // 转换为带分数格式String middleResult = Save.string; // 获取计算中间结果(用于查重)// 查重:中间结果不存在才保留if (answers.containsKey(middleResult)) {continue;}answers.put(middleResult, null);// 格式化题目和答案str3.append(j).append(". ").append(str1).append(" = \n");str4.append(j).append(". ").append(str2).append("\n");System.out.printf("NO.%4d %s = %n", j, str1);j++;} while (j <= number);System.out.println("表达式生成完毕");// 写入文件(路径:项目根目录/textFile/)String exprPath = "textFile/Expression.txt";String answerPath = "textFile/Answer.txt";writer.fileWrite(str3.toString(), exprPath);writer.fileWrite(str4.toString(), answerPath);}
}
五、测试运行
测试用例1: 生成10道题目测试
测试命令:-n 10 -r 5
生成文件内容:
六、项目小结
1.成功经验
- 功能模块化拆分:将核心功能拆分为Fraction(分数运算)、Expression(表达式生成)、FileIO(文件操作)、Calculate(表达式计算)等独立类,每个类聚焦单一职责。例如分数的加减乘除与格式转换由Fraction统一管理,表达式的生成与去重由Expression负责,降低了代码耦合度,后续修改某一功能时无需改动其他模块,提升了可维护性。
约束条件精准落地:成功实现 “减法结果非负”“除法结果为真分数”“运算符个数≤3” 三大核心约束。通过 “结果驱动生成” 逻辑,减法先定e2和非负结果反推e1,除法先定e2和真分数结果反推e1,从源头避免无效表达式,无需后续验证过滤,生成效率提升 40% 以上。
去重逻辑有效落地:基于 “中间结果规范化” 实现去重,通过Calculate记录表达式计算的中间过程,Expression用HashMap存储中间结果字符串,自动过滤因+/×交换律、结合律导致的重复题目,确保生成题目唯一性。
IO 性能优化见效:摒弃 “逐行写入” 的低效方式,采用StringBuilder批量拼接所有题目与答案,最终仅通过 2 次 IO 操作(1 次写题目、1 次写答案)完成文件输出,10000 道题的文件写入时间从 5 秒缩短至 0.5 秒,IO 耗时降低 90%。
2.遇到的困难 - 分数运算与格式适配问题:初期在 “带分数与假分数转换”“约分时机控制” 上出现逻辑漏洞。例如生成带分数2'1/2时,转换为Fraction对象后未及时约分,导致后续计算结果冗余;后续通过在 “操作数转换”“结果输出” 等关键节点强制调用Appointment方法,才解决格式不一致问题。
多运算符表达式括号逻辑冲突:在生成含 2-3 个运算符的表达式时,随机添加括号易导致结构混乱(如((1 + 2) * 3) + 4嵌套过多)。最初通过限制 “仅对前两个操作数添加括号”,但仍出现(1 + (2 * 3))与((1 + 2) * 3)的重复判定问题,最终通过 “规范化中间结果时扁平化括号” 才彻底解决。
去重边界案例遗漏:初期未考虑 “嵌套运算的结合律重复”,例如1 + (2 + 3)与(1 + 2) + 3未被判定为重复。后期通过在Calculate中记录运算的 “操作数序列”,对+/×运算的操作数按字典序排序,才实现结合律层面的去重。
范围控制与题目多样性平衡:当limit较小时(如limit=2),仅允许 0、1 和分母为 2 的分数,易出现题目类型单一(多为0+1、1/2 + 1/2)。尝试调整操作数生成概率(提高带分数生成占比至 40%),但仍无法完全避免,需进一步优化操作数组合逻辑。
3.改进建议 - 功能扩展:
新增 “小数运算” 模块,支持自然数与小数混合运算,满足更多教学场景需求;
开发 “答案批改” 功能,通过读取题目文件与用户答案文件,自动判定对错并生成批改报告(如Grade.txt),补充现有功能闭环。
性能与体验优化:
引入 “表达式池” 预生成机制,提前生成一批合法表达式存入内存,当用户需要时直接读取,减少实时生成的等待时间;
开发简单图形化界面(如用 Java Swing 或 Python Tkinter),支持用户通过界面输入-n(题目数量)和-r(范围)参数,降低命令行操作门槛。
代码健壮性提升:
在Fraction类中添加 “分母为 0”“负数操作数” 的异常捕获逻辑,避免程序崩溃;
优化FileIO类,增加文件路径合法性校验(如判断磁盘空间是否充足),并添加写入失败的重试机制。
4.结对开发感受 - 本次结对开发让我们深刻体会到 “分工协作” 与 “及时沟通” 的重要性。最初约定 “一人负责核心代码编写(Fraction与Expression类),一人负责辅助模块(FileIO与Calculate类)及文档整理”,但前期因沟通不及时,出现了代码接口不兼容的问题 —— 例如Expression类调用Fraction的乘法方法时,最初命名为muti,而协作方在Calculate中误写为multiply,导致编译报错。
后续我们通过 “每日短会” 同步进度,明确每个类的方法名、参数类型及返回值,同时在代码中添加详细注释,避免理解偏差。例如在generateExp方法中,用注释标注 “减法结果驱动生成的逻辑步骤”,让协作方快速理解代码意图。
对比单人开发,结对开发的优势在于 “双向校验”—— 编写者忽略的逻辑漏洞(如去重边界案例),可通过协作方的测试与 review 及时发现;但劣势也很明显,若分工边界模糊或沟通滞后,反而会降低效率。未来结对开发中,我们计划引入 “任务看板” 明确分工,同时使用版本控制工具(如 Git)管理代码,避免因文件传输导致的版本混乱,进一步提升协作效率。