一、预估与实际

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

二、需求分析

我通过百度查看一,二年数学教学大纲的方式了解到,小学一年级数学有如下的几个特点:

  • 特点1:

    • 都是一百以内加减法
  • 特点2:
    • 都是整数
  • 特点3:
    • 不会出现负数
  • 特点3:
    • 一年级只能是两位数加、减整十数和两位数加、减一位数
  • 特点4:
    • 二年级加法是两位数加减两位数
  • 特点4:
    • 二年级乘数法只能是表内乘法和表内除法

经过分析,我认为,这个程序应当:

  • 使用的数字大于0,小于100
  • 数字用int类型储存
  • 涉及减法时要注意相减不会出现负数
  • 对于main函数参数数组的长度判断,避免越界
  • 使用两个可变字符串储存将要输出到文件中的字符串

三、设计

1. 设计思路

  • 程序有一个类,四个方法,主要涉及到三种业务:

    • 对输入的参数进行判断,保证参数的合法性
    • 随机生成两个100以内的正整数,和运算符号并进行运算
    • 将生成的题目和答案写入out.txt中
  • 算法的关键:
    • 判断输入的参数是否合法,对于不合法的各种情况需给予提示
    • 生成的数字是否满足大纲要求时的判断逻辑

2. 实现方案

  • 准备工作:先在Github上创建仓库,克隆到本地,编写代码后通过git上传到Github上
  • 技术关键点:
  • 在判断用户输入时难点在于判断输入的数字不能过大,一年几的题目都是100以内,两个数组最多不超过10000种(如果考虑相减后无负数则会更少),命令行运行程序输入的参数储存在字符串中,所以可以通过判断字符串的长度不超过4,还有一个注意点对于输入0000001这中参数应该先将字符串的前导0去除后再判断
  • java中通过Math中random()方法生成一个0~1的小数,然后乘100取整得到需要的数字
  • 在生成随机数后需要针对加减乘除四种情况处理生成的数字,使之符合大纲要求
    • 加法:当第一个数大于0时,第二个数只能是小于10或者大于0且膜10等于0
    • 减法:先判断第一个和第二个数的大小,确保第一个数大于第二个数,再判断当第一个数大于0且第二个数也大于10时,第二个数等于它自身除10再乘10,以确保第二个数是一个整十数
    • 乘法:两个数都必须小于10
    • 除法:当第一个数是两位数时,第二个数必须小于10
  • 每次生成的题目和答案可以分别保存到两个StringBuffer对象中,然后通过字符流输入到文件中,注意保证文件路径必须存在,不存在的话需要创建路径

四、编码

  • 设计思路:

    • 先通过scanner函数接收用户的输入来进行调试,最后再改为使用main函数的参数。
    • 通过正则匹配输入的参数是否全为数字,然后检验数字的位数。
    • 通过Math.random()生成01的随机数,乘101再取整就可以生成0100的随机数
    • 生成的随机数%2得到0或1来代表 + 或 -
    • 确保生成的数符合大纲要求
    • 因为标准答案在所有题目之后,并且也包含题目,不能直接生成一道题就写入一道在文件中,所以采用两个StringBuffer对象分别保存,最后统一输入文件
    • 对于文件输入先判断文件路径是否存在,不存在要创建路径,再向文件中输入数据
  • 遇到的问题与解决方案:
    • 一开始直接检验位数是否大于9,后来经过讨论发现所以的题目中数不会超过10000,并且要先去除字符串的前导0,还有因为是通过正则去匹配是否全为数字,所以不需要再去额外判断是否为负数
    • 如果直接使用生成的随机数进行运算,相减会出现负数,后来加了一个判断,确保第一个数比第二个数大,如果不大就交换两个数
    • 在解决一年级减法中第二个数是整十或者一位数时,写好了逻辑判断但依然有吧符合数据的情况出现,原因在于之后又进行了交换两数,解决方案是先保证第一个数比第二个数大再去处理第二个数为整十(通过除10再乘10)
    • 在存入数据时,一开时想每生成一个数据存入一次,但这样就无法按照要求将标准答案输入到所有题目之后,后来使用两个StringBuffer对象先将题目和答案储存起来,最后同一输出
    • 一开始换行符使用\n 对于输出的文件用记事本打开没有换行,用编辑器打开才能看到换行,这样用户体验不好,后来改用System.lineSeparator()函数调用当前系统的换行符进行换行

1. 调试日志

  • 有几率出现java.lang.ArithmeticException / by zero 除零异常, 原因在于除法没有判断除数是否为0
  • 有几率出现死循环,原因是每次当生成的数字不符合大纲要求时就重新生成随机数,不能确保在有限时间内获得的想要的数字,解决方案只在每次生成新题目开始调用一次随机数的生成,在计算结果时争对加减乘除分别判断数字是否符合大纲要求,对于不符合的数字通过 / , % , *等运算进行处理达到要求不用再次循环生成随机数

2. 关键代码

/**
* 作用:生成题目
* @param len 用户要求生成的题目数量
* @param grade 年级
*/
private static void generatingTopic(int len,int grade) {
for (int i = 1; i <= len; i++) {
// 获取两个随机数,num1,num2表示参与计算的两个数字;
int num1 = (int) (Math.random() * 100);
int num2 = (int) (Math.random() * 100); // symbol代表运算符号;
int index = (1 == grade) ? ((int) (Math.random() * 10)) % 2 : ((int) (Math.random() * 10)) % 4;
String symbol = Operator[index]; //确保加法时和不超过100
while(0 == index && num1 + num2 >= 100) {
num1 = (int) (Math.random() * 100);
num2 = (int) (Math.random() * 100);
} // 计算结果
int res = 0;
int remainder = 0; // 余数
switch (symbol) {
case " + ":
// 确保小学1年级题目为两位数加减整十数和两位数加减一位数
if(1 == grade && num1>10 && num2 >10 && num1%10 != 0 && num2%10 !=0) {
num2 = num2/10*10;
}
res = num1 + num2;
break;
case " - ":
// 确保第一个数比第二个数大,避免相减出现负数,小学加减无负数
if (num1 < num2) {
int temp = num1;
num1 = num2;
num2 = temp;
}
// 确保小学1年级题目为两位数加减整十数和两位数加减一位数
if(1 == grade && num1>10 && num2 >10 && num2%10 !=0) {
num2 = num2/10*10;
}
res = num1 - num2;
break;
case " * ":
// 确保为表内乘法(两个数都为一位数)
num1 %= 10;
num2 %= 10;
res = num1 * num2;
break;
case " / ":
// 防止除数为0
while(0 == num2) {
num2 = (int) (Math.random() * 100);
} // 确保为表内除法(除数只能是一位数,不能使用%,因为又可能出现%的结果为0)
if(num2>10) {
num2 /=10 ;
} res = num1 / num2;
remainder = num1 % num2;
break;
}
// 将题目和答案记录到可变字符串中
topic.append("(" + i + ") " + num1 + symbol + num2 + System.lineSeparator());
if (symbol.equals(" / ")) {
standAnswer.append("(" + i + ") " + num1 + symbol + num2 + " = " + res
+ (remainder != 0 ? ("..." + remainder) : "") + System.lineSeparator());
} else {
standAnswer.append("(" + i + ") " + num1 + symbol + num2 + " = " + res + System.lineSeparator());
}
}
}

3. 代码规范

  • 第一条:类名使用UpperCamelCase风格,但是以下情形例外:DO / BO / DTO / VO / AO / PO 等。
  • 第二条:方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵循驼峰形式。
  • 第三条:大括号的使用约定。如果是大括号内为空,则简介地写成{}即可,不需要换行;如果是非空代码块则:
    • 左大括号前不换行。
    • 左大括号后换行。
    • 右大括号前换行。
    • 右大括号后还有 else 等代码则不换行;表示终止的右大括号后必须换行。
  • 第四条:左小括号和字符之间不出现空格;同样的,有小括号和字符之间也不出现空格。详见第5条下面正例提示。

    反例:if (空格 a == b 空格)
  • 第五条: if/for/while/switch/do等保留字与括号之间都必须加空格。
  • 第六条:任何二目、三木运算符的左右两边都需要加一个空格。 说明:运算符包括赋值运算符=、逻辑运算符&&、加减乘除符号等。
  • 第七条:不同逻辑、不同语义、不同业务的代码之间插入一个空行分割开来以提升可读性。
  • 第八条:在一个switch块内,每一个case要么通过break/return等来终止,要么注释说明程序将继续执行到哪一个case为止;在一个switch块内,都必须包含一个default语句并且放在最后,即使空代码。

五、测试

测试 预期结果 实际结果
java MathExam6313 运行程序时请输入两个数字代表要生成的题数和年级。 运行程序时请输入两个数字代表要生成的题数和年级。
java MathExam6313 10 小学1年级数学题题目已生成,请查看out.txt文件 小学1年级数学题题目已生成,请查看out.txt文件
java MathExam6313 10 2 小学2年级数学题题目已生成,请查看out.txt文件 小学2年级数学题题目已生成,请查看out.txt文件
java MathExam6313 10 1 小学1年级数学题题目已生成,请查看out.txt文件 小学1年级数学题题目已生成,请查看out.txt文件
java MathExam6313 000000000001 1 小学1年级数学题题目已生成,请查看out.txt文件 小学1年级数学题题目已生成,请查看out.txt文件
java MathExam6313 000000000001 2 小学2年级数学题题目已生成,请查看out.txt文件 小学2年级数学题题目已生成,请查看out.txt文件
java MathExam6313 10 3 输入的第二个参数不是1或2,请重新运行,第二个参数输入1或2 输入的第二个参数不是1或2,请重新运行,第二个参数输入1或2
java MathExam6313 100 1 1 最多输入两个个数字参数,第一个代表题目数量,第二个代表年级 最多输入两个个数字参数,第一个代表题目数量,第二个代表年级
java MathExam6313 cbsckj 1 输入的第一个参数不是正整数,请重新运行,输入一个正整数 输入的第一个参数不是正整数,请重新运行,输入一个正整数
java MathExam6313 10 dsv 输入的第二个参数不是1或2,请重新运行,第二个参数输入1或2 输入的第二个参数不是1或2,请重新运行,第二个参数输入1或2
java MathExam6313 9999999999999999 第一个参数数字过大,请重新运行,输入参数 第一个参数数字过大,请重新运行,输入参数

六、总结

  • 一开始的时候只是想了一下主要的流程,然后直接在main函数中直接敲代码,最后让整个程序显得又臭又长,拥挤不堪.尤其在调试程序修改代码时,让人头大。后来重构代码,将整个业务逻辑分为三个功能,每个功能一个函数,整个代码立马变得清晰起来。
  • 一定要先写注释,再写代码,每一个代码块之间的结构要明确、清晰
  • 一定要先写注释,再写代码,每一个代码块之间的结构要明确、清晰
  • 一定要先写注释,再写代码,每一个代码块之间的结构要明确、清晰
  • 我自己写代码时是会先写注释再写代码,但是在帮其他同学解决问题时发现,基本数大家都不写注释,或者只有零零散散的一点注释,代码块之间的缩进也是混乱的,光看代码就要看好久,才明白他写的是什么,找bug就更难了,代码写清晰了,与人方便,于己方便,先写注释还有一个好处就是帮助自己理清逻辑,当注释写好了,逻辑清楚了,剩下的就像填空题一样了,so easy, too happy
  • 还有就是需求分析要弄好,不然代码敲了半天,最后还要反工,我做这道题就是一开始相当然的认为一年级的题目就只是100以内加减法而已,但后来仔细阅读了教学大纲和练习册才发现还有一些其他要求,这时候看着长长的代码欲哭无泪,又得吭哧吭哧改代码
  • 每写一个功能就测试一下,这样也可以减少后期bug修改的次数,不然写了半天运行结果发现前面某行代码出错,找bug都要找好久

so easy, too happy的更多相关文章

  1. 【转】Windows下使用libsvm中的grid.py和easy.py进行参数调优

    libsvm中有进行参数调优的工具grid.py和easy.py可以使用,这些工具可以帮助我们选择更好的参数,减少自己参数选优带来的烦扰. 所需工具:libsvm.gnuplot 本机环境:Windo ...

  2. Struts2 easy UI插件

    一.easy UI是类似于jQuery UI的插件库,它提供了丰富的各种常用插件:tree.datagrid... tree插件: 语法:$(selector).tree([settings]); 常 ...

  3. Easy UI常用插件使用

    一.easy UI是类似于jQuery UI的插件库,它提供了丰富的各种常用插件:tree.datagrid... tree插件: 语法:$(selector).tree([settings]); 常 ...

  4. UVA-11991 Easy Problem from Rujia Liu?

    Problem E Easy Problem from Rujia Liu? Though Rujia Liu usually sets hard problems for contests (for ...

  5. CodeForces462 A. Appleman and Easy Task

    A. Appleman and Easy Task time limit per test 1 second memory limit per test 256 megabytes input sta ...

  6. easy ui插件

    简介: easy UI是类似于jQuery UI的插件库 注意:多脚本同时使用时,注意脚本冲突问题. 常用插件: 1.tree插件(tree插件实现动态树形菜单) 2.datagrid插件(datag ...

  7. 用TPP开启TDD的easy模式

    Test-Drived Development 测试驱动开发三步曲:写一个失败的测试用例->编写生产代码通过这个测试用例(transformation)->重构(refactor).重构是 ...

  8. Easy Sysprep更新日志-skyfree大神

    Easy Sysprep更新日志: Skyfree 发表于 2016-1-22 13:55:55 https://www.itsk.com/forum.php?mod=viewthread&t ...

  9. [官方软件] Easy Sysprep v4.3.29.602 【系统封装部署利器】(2016.01.22)--skyfree大神

    [官方软件] Easy Sysprep v4.3.29.602 [系统封装部署利器](2016.01.22) Skyfree 发表于 2016-1-22 13:55:55 https://www.it ...

  10. [原创] Easy SysLite V1.2 (2016.5.29更新,新增加WIN10支持,一个程序适配所有系统减肥)

    [原创] Easy SysLite V1.2 (2016.5.29更新,新增加WIN10支持,一个程序适配所有系统减肥) nohacks 发表于 2016-5-29 17:12:51 https:// ...

随机推荐

  1. P1063 能量项链

    题目描述 在Mars星球上,每个Mars人都随身佩带着一串能量项链.在项链上有N颗能量珠.能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数.并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定 ...

  2. Linux下如何查看分区文件系统类型

    1,fdisk -l fdisk -l 只能列出硬盘的分区表.容量大小以及分区类型,但看不到文件系统类型. 2,df -h df 命令是用来查看文件系统磁盘空间使用量的.但df 命令只会列出已挂载的文 ...

  3. Spring Cloud和Dubbo整合开发笔记(1)

    一.需求背景: 公司内部老项目微服务技术栈使用Dubbo, 新项目技术栈使用主流的Spring Cloud相关组件开发,新旧项目涉及交互调用,无法直接通信数据传递. 老项目基于Dubbo,重构代码升级 ...

  4. java官网门户源码 SSM框架 自适应-响应式 freemarker 静态模版引擎

    来源:http://www.fhadmin.org/webnewsdetail3.html 前台:支持(5+1[时尚单页风格])六套模版,可以在后台切换 官网:www.fhadmin.org 系统介绍 ...

  5. mysql 跑存储过程没有权限的问题

    1.赋予权限 GRANT ALL PRIVILEGES ON *.* TO root@"%" IDENTIFIED BY "root"; 2.刷新权限 FLUS ...

  6. PHP中的call_user_func()与call_user_func_array()简单理解

    原文地址:http://small.aiweimeng.top/index.php/archives/52.html call_user_func:把一个参数作为回调函数调用 用法说明: call_u ...

  7. python爬虫-execjs使用

    python爬虫-execjs使用 ecexjs的作用 通过python代码去执行JavaScript代码的库 execjs的安装 pip install PyExecJS execjs使用之前,得先 ...

  8. 20155212 C语言实现linux下pwd命令的两种方法

    20155212 C语言实现linux下pwd命令的两种方法 学习pwd命令 通过man pwd命令查看 pwd [OPTION],一般不加参数 -P显示当前目录的物理路径 -L显示当前目录的连接路径 ...

  9. mtr语言真是逆天了

    实践证明,设计一个语言,还不是简单的解释没一行哦

  10. APP测试基本流程以及APP测试要点

    APP测试流程梳理 APP测试要点梳理 链接:http://pan.baidu.com/s/1gfaEZ1x 密码:07yt 1 APP测试基本流程 1.1流程图 1.2测试周期 测试周期可按项目的开 ...