大气而又可爱,机智不失优雅的标题君
一、预估与实际
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
• Estimate | • 估计这个任务需要多少时间 | 490 | 1160 |
Development | 开发 | ||
• Analysis | • 需求分析 (包括学习新技术) | 10 | 30 |
• Design Spec | • 生成设计文档 | 10 | 10 |
• Design Review | • 设计复审 | 10 | 10 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 20 | 30 |
• Design | • 具体设计 | 20 | 40 |
• Coding | • 具体编码 | 360 | 900 |
• Code Review | • 代码复审 | 40 | 60 |
• Test | • 测试(自我测试,修改代码,提交修改) | 10 | 30 |
Reporting | 报告 | 10 | 20 |
• Test Repor | • 测试报告 | 10 | 20 |
• Size Measurement | • 计算工作量 | 10 | 10 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 10 | 20 |
合计 | 1160 |
二、需求分析
通过网络,我找到了电子版本的人教版小学一二年级课本并快速阅读完毕。经过阅读我发现两本书有以下特点。
一年级:
- (1) 内容包含一百以内的加减法,大多数例题的答案也不存在超过一百的数字
- (2) 可以进行三位参数的加减
- (3) 暂时还不涉及负数。
二年级:- (1) 开始涉及万以内的加减法
- (2) 乘法和除法都是表内乘除法
- (3)除法中除数是9以内的,被除数为一百以内。
经过分析,我认为,这个程序应当:
一年级:
- (1)加数所使用的数字应该小于100且和不大于100
- (2)减数所使用的数字应该不大于100且减数小于被减数
- (3) 如果存在空余时间修改代码尝试写三位数之间的加减
二年级:- (1) 在一年级的基础上将加减数的大小扩大到一万以内
- (2) 乘数所使用的数字应该小于等于9
- (3) 被除数所使用的数字应该小于一百,除数所使用的数字应该小于等于9
三、设计
1. 设计思路
这个程序有七个函数。
- 第一个主函数负责主流程的代码运行。
- 第二个函数input函数负责对输入的数据进行规范,如果格式错误提示错误并结束程序。
- 第三个函数math函数负责区分年级所需要用到的运算规则,随机出题进行四则运算并写入文档
- 创建四个函数multiplication函数,division函数,addition函数,subtraction函数分别负责四个运算。
大致运算图如上。
我们可以输入我们想要生成的题目数量,在input函数中对我们输入的数据进行一个是否会影响到后期运行的格式判断,如果会,提出错误提示并让用户重新输入。接下来在math函数中根据用户的年级和所需要的题目数量进行一个分类,并通过random函数随机调用四个运算方法进行运算将答案存入数组并写入题目。调用结束在math函数中进行文档写入,拷贝已经写好的题目并添加储存在数组中的答案。最后结束程序。
2. 实现方案
- 准备工作:先在Github上创建仓库,克隆到本地。
- 具体流程:设计并编写代码。测试数据。修改简化代码及算法。提交代码,写博客。
- 技术关键点:正则表达式,IO流
四、编码
问题1:在使用random()函数时使用Math.random()*1无法取到1
解决过程:通过其他人的博客详细了解到random()函数生成的随机数为double类函数强制转换为int类型时导致取到1的概率接近为0,于是我修改了生成范围。问题2:在进行对目标文件边读边写的过程中使循环陷入了死循环。
解决过程:设置读取文件时按行读文件,一旦读到设置题目的题数,退出循环。问题3:无法实现在使用命令行参数接收一个n,只能完成开始运行java程序后输入n
解决过程:通过网络了解到命令行将其储存在args数组中问题4:编写除法方法模块的时候没有办法同时返回两个数值(查阅网络有方法但是代码太过冗余)。尝试返回数组又遇到同时执行了两遍这个函数的问题
解决过程:尝试了很多方法才想出来调用函数的时候直接传入数组在数组上进行数据储存问题5:在编写任务二的代码的时候尝试写在输入数据格式错误的时候提供提示并让用户重新输入。但重新输入上遇到了很多无法解决的问题。
解决过程:有一个用递归来写的想法但还未尝试。
1. 调试日志
我编写的代码在除法部分的函数一开始是传入一个 i(第i道题目)。在这道题中随机生成被除数和除数,并进行运算将得到的商和余数的部分返回赋值给原先设定好的两个数组进行储存。两个部分代码如下:
//除法方法代码
public static int[] division(int i,OutputStream out) {
int a =(int) (Math.random()*100);
int b =(int) (1+Math.random()*9);
String word=("("+(i+1)+") "+a +" / "+ b +" = ")+"\n";
try {
out.write(word.getBytes());
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
int str[] =new int[2];
str[0]=a/b;
str[1]=a%b;
return str;
}
//第二段代码
intArray[i]=division(i,out)[0];
intArray1[i]=division(i,out)[1];
在这个时候我尝试执行代码但得到的数据在遇到除法运算时会随机多生成两道题目并且结果错误。
我开始在除法运算方法的部分设置断点。发现我在第二段的代码所运算的是将除法运算进行了两遍而并不是存储同一个函数中的商和余数。我开始转化思路,比起从函数中返回两个数据存储到设置的数组中不如直接传入数组进行存储。于是开始修改代码最终得到如下可以运行。
public static void division(int i,OutputStream out,int intArray[],int intArray1[]) {
int a =(int) (Math.random()*100);
int b =(int) (1+Math.random()*9);
String word=("("+(i+1)+") "+a +" / "+ b +" = ")+"\n";
try {
out.write(word.getBytes());
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
intArray[i]=a/b;
intArray1[i]=a%b;
}
2. 关键代码
Scanner scanner0=new Scanner(file);
int i=0;
while(scanner0.hasNextLine()&&(i!=n)) {
if(intArray1[i]==0) {
word =(scanner0.nextLine())+intArray[i]+"\n";
}
else {
word =(scanner0.nextLine())+intArray[i]+"..."+intArray1[i]+"\n";
}
out.write(word.getBytes());
i++;
}
我展示的是在答案分割线以后再文档上写入题目和答案的一段代码。
这段代码通过边写边读的方式对文档中写好的题目进行一次拷贝。Scanner按行读的方式十分便捷,同时设定i(当前题数)不等于n(题目总数)避免了出现死循环循环读数据的情况。每读一行问题对问题进行拷贝,并添加存储在intArray数组中答案和intArray1数组中的商完成文档。
3. 代码规范
请给出本次实验使用的代码规范:
- 静态变量(static)前面加上小写s
- 任何二目、三木运算符的左右两边都需要加一个空格。
- 在 if/else/for/while/do 语句中必须使用大括号。即使只有一行代码,避免采用单行的编码方式:if (condition) statements;
- 谨慎注释掉代码。在上方详细说明,而不是简单地注释掉。如果无用,则删除。
- 在使用正则表达式时,利用好其预编译功能,可以有效加快正则匹配速度。
- 注意 Math.random() 这个方法返回是 double 类型,注意取值的范围 0≤x<1(能够取到零值,注意除零异常),如果想获取整数类型的随机数,不要将 x 放大 10 的若干倍然后取整,直接使用 Random 对象的 nextInt 或者 nextLong 方法。
- 任何数据结构的构造或初始化,都应指定大小,避免数据结构无限增长吃光内存。
- 避免出现重复的代码(Don’t Repeat Yourself),即 DRY 原则。
五、测试
任务 | 输入数据 | 输出结果 |
---|---|---|
任务一 | 输入a b | 提示“请输入单个参数”并能够重新输入 |
任务一 | 再次输入a b | 提示“请输入正确字符”并能够重新输入 |
任务二 | 输入12 | 提示“"输入的参数应为两个参数"程序结束 |
任务二 | 输入-1 | 提示"输入的参数应为数字且不为-1" |
任务二 | 输入12 2 | 正常运行程序 |
六、总结
-我认为我在尽力去达成“”软件开发的基本策略:分而治之”,但看完全部代码,我知道我仍然做的不够,代码冗余,可以简化的地方还有很多,例如因为时间限制在除法方法所写的一个可以节省时间空间的小方法并没有在提交之前应用到其他算术方法。
-“在高质量的设计、规范的编码以及有效的测试是保证软件产品质量的三个重要方面”我也认为我做的仍然不够。我对软件需求调查仅限于阅读完一二年级的电子课本,但在悄悄咪咪读了一会别人的博客,我发现别人在做的更多,例如查阅教案。规范的编码也是只做到了零零散散,编程习惯是需要长期养成,但我现在就需要开始改正。做的不够的还有是完成需求,在了解出题内容可包含三个参数的时候我没有去编写代码去完成,或许是时间不够,但未来更是没有时间让我去细想这些内容。以及在完成整个项目的过程,我了解到我在java上知识了解的稀缺