软件工程第三次作业
要求0:作业地址: https://edu.cnblogs.com/campus/nenu/2016CS/homework/2266
要求1:https://git.coding.net/tangjh563/f4.git
要求2:
一、编程队友吕鹏鹏及博客地址: https://www.cnblogs.com/lvpengaaron/
二、问题分析:
一个基于控制台的四则运算系统,要能实现生成并计算含有真,假分数,整数的不超过三个运算符带有括号的四则运算表达式,并且要能根据用户所提交的答案生成答题报告,答题报告中主要包括,本次答题的正确,错误,和重复表达式出现的情况。生成的表达式和答案要存入文件中。对生成的表达式有如下要求,不能在过程中产生负数,因为小学生并不会计算负数,以及不能出现除0的情况,因为小学生不会计算除以0。
从整个需求来看,大致可以分为三个模块,生成表达式,表达式计算(包括将表达式和答案写入文件),答题报告的生成(包括表达式的查重和根据输入完成的校验)。各个模块之间关系密切,故采用由下至上的不断迭代的开发模式,先开发最底层的各个桩模块,在开发每个桩模块时再采用测试驱动开发的方法,从编写小的测试用例开始开发桩模块,当对桩模块进行整合时,再编写测试模块,这样当开发完成后测试也就完成了。
所谓相同的运算过程就是,你在做什么运算我也做什么运算,你的操作数是啥我的操作数也是啥,出于这个引入一个新的表达式,我将其命名为查重表达式,他的结构是运算在先后面跟着这个运算符的操作数,如(1+2)*3+5的查重表达式就为: +12 * 3 +5 这个表达式的含义就是第一个运算的是加法,加法的操作数是2 和3 第二个运算是乘法,乘法的操作数是前一步计算的结果和3以此类推,而3*(1+2) +5的查重表达式为:+12 * 3+5 与上述完全一致!这样在做查重是只需判断查重表达式是否一致或者在查重表达式中第一个字符为‘+’ 或者‘*’的情况下后续的两个操作数互换位置后是否一致即可。也就是说上述的查重表达式于+21 * 3+5 也是等价的。
那该如何生成查重表达式,所谓的查重表达式就是描述表达式正在运算的过程,那就在你使用后缀表达式计算时,去生成即可。算法之后给出
三、功能设计:
在四则运算项目.zip中
com.wx.appEntrance是作为项目的入口。
com.wx.test 是作为测试功能使用
com.wx.randomTool是作为生成随机的四则运算表达式的,共有四个类组成其中RandExpressionExport(可直接生成表达式)是顶层类,是对RandOperatorNumberExport(可随机生成各类操作数和操作符)进一步封装,而RandOperatorNumberExport是对RandomExportMachine(可生成数字和字符)的进一步封装,Ruler则是描述生成表达式的功能.
com.wx.expression是描述表达式的结构
com.wx.calculateTool是用于计算表达式,PostfixExpression用于生成后缀表达式,CalculateRuler描述计算规则,CalculateExpression顶层类对可直接计算表达式,对前面两个类的封装。
com.wx.fileIO用于实现文件操作
com.wx.expressionCnki 用于实现表达式的查重,工具类.
com.wx.report 用于生成答题报告.
四、收获与不足:
收获:在这次编程过程中,遇到了很多细节性的问题,有一种每次细想一遍就会发现一个小问题的感觉。在解决问题的过程中,又重新复习了数据结构和算法程序设计的相关知识,用到了栈的存储、中缀表达式与后缀表达式的转化等。最大的感受就是在上网查阅资料的时候,看了挺多代码,了解借鉴了别人的编程思想,get到了很多用Java编程的小技巧。
不足:有些功能和格式不能完美实现。
五、重要代码
1、用于描述计算规则的CalculateRuler中的用于化简表达式的方法simplificationFracrion的代码如下:
2、用于实现查重的Cnki类中的得到查重表达式的getCnkiExpressionArray方法的代码如下:
3、用于实现查重的Cnki类中的判断两个表达式是否重复的代码如下:
4、生成报告代码:
package com.wx.report;
import com.wx.expression.Expression;
import com.wx.expressionCnki.Cnki;
/**
*
* @author wx
*
*该类用作生成答题报告,包括两部分,第一部分为答案校验的报告
*第二部分为查重结果的报告
*/
public class AnswerResport {
private static Cnki cnki = new Cnki();// 用于查重校验
/**
*
* @param replyAnswer 用户的回答
* @param rightAnswer 正确的答案
* @return 答案的答题报告
*/
public static String getAnswerResport(String []replyAnswer,String[] rightAnswer){
String rightAnswerResport = "Correct: ",rightAnswerList = "正确的题号";//构造正确部分呢过的答题报告
String wrongAnswerResport = "Wrong",wrongAnswerList = "错误的题号";//构造错误部分呢过的答题报告
int rightNumber = 0,wrongNumber = 0;//记录正确和错误的个数
for(int i = 0;i<replyAnswer.length;i++){//开始校验用户的回答
if(replyAnswer[i].equals(rightAnswer[i])){//答对
rightNumber++;
rightAnswerList = rightAnswerList+ (i+1)+",";
}else{//答错
wrongNumber++;
wrongAnswerList = wrongAnswerList + (i+1) +",";
}
}
rightAnswerResport = rightAnswerResport+rightNumber+"-------"+rightNumber+"道题正确, "+rightAnswerList+"\n";
wrongAnswerResport = wrongAnswerResport+wrongNumber+"-------"+wrongNumber+"道题正确,"+wrongAnswerList+"\n";
return rightAnswerResport+wrongAnswerResport;
}
/**
*
* @param expression 要查重的表达式数组
* @return 查重报告
*/
public static String cnkiExpressionAnswerReport(Expression [] expression){
String cnkiReport = "Repeat:"; //返回的表达式报告
String temp = "";
String tempReport = ""; // 临时变量,用于出现一次重复情形所产生的信息.
int repeatNumber = 0; // 计数出现重复表达式的次数.
int findRepeatFlag = 0; //标志是否找到重复的表达式
for(int i = 0;i<expression.length-1;i++){ //双重循环验证表达式
if(expression[i].getCnkiFlag()==1) continue; //若是已经被标记为重复的则跳过继续下一个表达式
for(int j = i+1;j<expression.length;j++){
if(expression[j].getCnkiFlag()==1) continue;//若是已经被标记为重复的则跳过继续下一个表达式
// System.out.print(i+" "+j+"查重结果"+cnki.cnkiExression(expression[i],expression[j]));
if(cnki.cnkiExression(expression[i],expression[j])){ //出现重复的表达式
expression[i].setCnkiFlag(1); //设置重复标志
expression[j].setCnkiFlag(1); //设置重复标志
findRepeatFlag = 1;
temp = temp + (j+1) +","+expression[j].getExpression()+" ";
}
if(findRepeatFlag == 1) {//找到重复的
repeatNumber++;
findRepeatFlag = 0;//重置标志
tempReport = "("+ (repeatNumber)+")"+ (i+1)+", "+expression[i].getExpression() +" Repeat " +tempReport +temp;//构造单次重复报告
temp = "";
}
}
}
cnkiReport = cnkiReport+repeatNumber;
if(repeatNumber!=0){
cnkiReport = cnkiReport+"\n"+"RepeatDetail:\n"+tempReport;
}
return cnkiReport;
}
}
PSP
PSP2.1 | Personal Software Process Stages | Estimated time(min) | actual time(min) |
Planning | 计划 | 30 | 25 |
· Estimate | 估计这个任务需要多少时间 | 740 | 800 |
Development | 开发 | 80 | 90 |
· Analysis | 需求分析 (包括学习新技术) | 10 | 10 |
· Design Spec | 生成设计文档 | 7 | 10 |
· Design Review | 设计复审 | 6 | 5 |
· Coding Standard | 代码规范 | 4 | 5 |
· Design | 具体设计 | 300 | 400 |
· Coding | 具体编码 | 350 | 400 |
· Code Review | 代码复审 | 10 | 15 |
· Test | 测试(自我测试,修改代码,提交修改) | 15 | 15 |
Reporting | 报告 | 20 | 25 |
· | 测试报告 | 5 | 5 |
· | 计算工作量 | 4 | 7 |
· | 并提出过程改进计划 | 4 | 4 |
总结: 在做作业的时候,体会到了逻辑清晰是有多重要,不管编程能力怎么样,首先看见一道题目时不要急着就去做,想想如何做怎么做才是最重要的,如果逻辑清晰知道需要建几个类,每个类包含什么,每个类之间的关系是什么,就算个别方法不会写,大体的模子也能画出来,最后要就个别函数即可。下次我做作业的时候应该会多花时间在逻辑分析,流程图上。