软件工程第三次作业 结对编程
结对编程
小组成员:
201521123055 林一心 博客地址
201521123046 张杭镖 博客地址
项目地址
一、分析改进现有代码
1.单元测试:
2.覆盖率:
3.确定当前设计的一个弱点,通过重构,确保在这个地方已有测试覆盖并保证重构没有改变已有的功能:
原程序只能生成两个数之间的算式,并且分数与整数算式出现几率没设置正确。
4.修改代码后,检查代码覆盖,看单元测试是否需要修改?测试用例是否需要增加?
单元测试需要修改,因为添加了多个数字的运算。
二、功能扩展
增加了括号运算符,相应的计算函数也要添加括号运算符的处理,原代码把计算过程放在main生成算式的main类中处理,扩展功能后代码显得臃肿,因此单独把计算功能拉出来做一个Calculator类。(这个计算功能同样也支持多位整数的计算,以便小学生升级到进阶地狱)
核心代码:
生成题目
public main()//生成四则运算并输出
{
new Thread(myTimeRunable).start();
int n = 0;
MainFrame ma= new MainFrame();
try{
//调用初始化方法
jbInit();
}
catch(Exception exception){
exception.printStackTrace();
}
try{
n= Integer.parseInt(ma.number);
}catch(NumberFormatException e){
//利用消息对话框提示输入失败
JOptionPane.showMessageDialog(this,"输入错误!请重新输入");
}
int m = (int)(Math.random()*n+1);//随机整数题目和分数题目的题量
for(int j=0;j<(n-m);j++){//整数题目
int no=(int)(Math.random()*3+1); //最多四个数字运算
StringBuffer qustr=new StringBuffer("");
String ans;
int numm=(int)(Math.random()*9+1);//随机数字
qustr.append(numm);
for(int i=0;i<no;i++){
numm=(int)(Math.random()*9+1);
int op=(int)(Math.random()*4+1);//随机选择计算符
if(op==1){//加法
qustr.append("+"+numm);
//Answer.add(num1+num2+"");
}
if(op==2){
qustr.append("-"+numm);
}
if(op==3){//乘法
qustr.append("*"+numm);
}
if(op==4){//除法
i--;
continue;
}
}
if(no>=2) {
int left_kuo = (int) (Math.random() * no + 1);
int right_kuo = (int) (Math.random() * (no+1 - left_kuo) + 1 + left_kuo);
qustr.insert(2*(left_kuo-1), '(');
qustr.insert(2*right_kuo, ')');
}
qustr.append('=');
Question.add(qustr.toString());
Calculator cal=new Calculator();
Answer.add(""+cal.caculate(qustr.toString()));
}
for(int j=0;j<m;j++){//分数题目
Scanner in = new Scanner(System.in);//真分数的计算
int op=(int)(Math.random()*4+1);
int[] f1 =createFraction();
int[] f2 =createFraction();
int j1=GCD(f1[0],f1[1]);
f1[0]=f1[0]/j1;//化简分数
f1[1]=f1[1]/j1;
j1=GCD(f2[0],f2[1]);
f2[0]=f2[0]/j1;
f2[1]=f2[1]/j1;
int gbs = LCM(f1[1],f2[1]);
if(op==1){//加法
Question.add("("+f1[0]+"/"+f1[1]+")+("+f2[0]+"/"+f2[1]+")=");
int num1=f1[0]*f2[1]+f2[0]*f1[1];
int num2=f1[1]*f2[1];
int num3=GCD(num1,num2);
num1=num1/num3;
num2=num2/num3;
String a=new String();
if(num1==num2)
{
a="1";
}
else {
a = num1 + "/" + num2;
}
Answer.add(a+"");
}
if(op==2){//减法
int num1=f1[0]*f2[1]-f2[0]*f1[1];
if(num1>0){ //防止出现负数
Question.add("("+f1[0]+"/"+f1[1]+")-("+f2[0]+"/"+f2[1]+")=");
int num2=f1[1]*f2[1];
String a=new String();
if(num1==0)
{
a="0";
}
else
{
int num3=Math.abs(GCD(num1,num2));
num1=num1/num3;
num2=num2/num3;
if(num1==num2)
{
a="1";
}
else
{
a=num1+"/"+num2;
}
}
Answer.add(a+"");
}else{
Question.add("("+f2[0]+"/"+f2[1]+")-("+f1[0]+"/"+f1[1]+")=");
int num11=f2[0]*f1[1]-f1[0]*f2[1];
int num2=f1[1]*f2[1];
String a=new String();
if(num11==0)
{
a="0";
}
else
{
int num3=Math.abs(GCD(num11,num2));
num11=num11/num3;
num2=num2/num3;
if(num11==num2)
{
a="1";
}
else
{
a=num11+"/"+num2;
}
}
Answer.add(a+"");
}
}
if(op==3){//乘法
Question.add("("+f1[0]+"/"+f1[1]+")*("+f2[0]+"/"+f2[1]+")=");
int num1= f1[0]*f2[0];
int num2 = f1[1]*f2[1];
int num3=GCD(num1,num2);
String a=new String();
num1= num1/num3;
num2 = num2/num3;
if(num1==num2)
{
a="1";
}
else
{
a=num1+"/"+num2;
}
Answer.add(a+"");
}
if(op==4){//除法
Question.add("("+f1[0]+"/"+f1[1]+")÷("+f2[0]+"/"+f2[1]+")=");
int num1= f1[0]*f2[1];
int num2 = f1[1]*f2[0];
int num3=GCD(num1,num2);
String a=new String();
num1= num1/num3;
num2 = num2/num3;
if(num1==num2)
{
a="1";
}
else
{
a=num1+"/"+num2;
}
Answer.add(a+"");
}
}
//输出题目
JTextArea0.setText("");
for(String string : Question){
num ++;
JTextArea0.append("("+num+")、"+string+"\n");
}
}
计算
public class Calculator {
private Stack<Long> numberStack = null;
private Stack<Character> symbolStack = null;
public long caculate(String numStr) {
// 初始化栈
numberStack = new Stack<Long>();
symbolStack = new Stack<Character>();
// 用于缓存数字,因为数字可能是多位的
StringBuffer temp = new StringBuffer();
// 从表达式的第一个字符开始处理
for (int i = 0; i < numStr.length(); i++) {
char ch = numStr.charAt(i); // 获取一个字符
if (isNumber(ch)) { // 若当前字符是数字
temp.append(ch); // 加入到数字缓存中
} else { // 非数字的情况
String tempStr = temp.toString(); // 将数字缓存转为字符串
if (!tempStr.isEmpty()) {
long num = Long.parseLong(tempStr); // 将数字字符串转为长整型数
numberStack.push(num); // 将数字压栈
temp = new StringBuffer(); // 重置数字缓存
}
// 判断运算符的优先级,若当前优先级低于栈顶的优先级,则先把计算前面计算出来
while (!comparePri(ch) && !symbolStack.empty()) {
long b = numberStack.pop(); // 出栈,取出数字,后进先出
long a = numberStack.pop();
// 取出运算符进行相应运算,并把结果压栈进行下一次运算
switch ((char) symbolStack.pop()) {
case '+':
numberStack.push(a + b);
break;
case '-':
numberStack.push(a - b);
break;
case '*':
numberStack.push(a * b);
break;
case '/':
numberStack.push(a / b);
break;
default:
break;
}
} // while循环结束
if (ch != '=') {
symbolStack.push(new Character(ch)); // 符号入栈
if (ch == ')') { // 去括号
symbolStack.pop();
symbolStack.pop();
}
}
}
} // for循环结束
return numberStack.pop(); // 返回计算结果
}
private String removeStrSpace(String str) {
return str != null ? str.replaceAll(" ", "") : "";
}
private boolean isStandard(String numStr) {
if (numStr == null || numStr.isEmpty()) // 表达式不能为空
return false;
Stack<Character> stack = new Stack<Character>(); // 用来保存括号,检查左右括号是否匹配
boolean b = false; // 用来标记'='符号是否存在多个
for (int i = 0; i < numStr.length(); i++) {
char n = numStr.charAt(i);
// 判断字符是否合法
if (!(isNumber(n) || "(".equals(n + "") || ")".equals(n + "")
|| "+".equals(n + "") || "-".equals(n + "")
|| "*".equals(n + "") || "/".equals(n + "")
|| "=".equals(n + ""))) {
return false;
}
// 将左括号压栈,用来给后面的右括号进行匹配
if ("(".equals(n + "")) {
stack.push(n);
}
if (")".equals(n + "")) { // 匹配括号
if (stack.isEmpty() || !"(".equals((char) stack.pop() + "")) // 括号是否匹配
return false;
}
// 检查是否有多个'='号
if ("=".equals(n + "")) {
if (b)
return false;
b = true;
}
}
// 可能会有缺少右括号的情况
if (!stack.isEmpty())
return false;
// 检查'='号是否不在末尾
if (!("=".equals(numStr.charAt(numStr.length() - 1) + "")))
return false;
return true;
}
private boolean isNumber(char num) {
if (num >= '0' && num <= '9')
return true;
return false;
}
private boolean comparePri(char symbol) {
if (symbolStack.empty()) { // 空栈返回ture
return true;
}
char top = (char) symbolStack.peek();
if (top == '(') {
return true;
}
// 比较优先级
switch (symbol) {
case '(': // 优先级最高
return true;
case '*': {
if (top == '+' || top == '-') // 优先级比+和-高
return true;
else
return false;
}
case '/': {
if (top == '+' || top == '-') // 优先级比+和-高
return true;
else
return false;
}
case '+':
return false;
case '-':
return false;
case ')': // 优先级最低
return false;
case '=': // 结束符
return false;
default:
break;
}
return true;
}
}
运行结果:
效能分析:
三、小结感受
结队编程在大二学习JAVA时有尝试过,只是初步体验了一下,这次与大佬结队希望真的能够学到东西提升自己,有个领航员,可以时刻发现问题。两人一起寻找问题发现问题感觉效率比较高,但编程过程还是比较坎坷,希望最后能够一加一大于二,乃至远大于二。
PSP2.1 | 个人开发流程 | 预估耗费时间(分钟) | 实际耗费时间(分钟) |
---|---|---|---|
Planning | 计划 | 15 | 8 |
Estimate | 明确需求和其他相关因素,估计每个阶段的时间成本 | 10 | 4 |
Development | 开发 | 120 | 140 |
Analysis | 需求分析需求分析 (包括学习新技术) | 10 | 10 |
Design Spec | 生成设计文档 | 0 | 0 |
Design Review | 设计复审 | 10 | 8 |
Coding Standard | 代码规范 | 2 | 2 |
Design | 具体设计 | 10 | 15 |
Coding | 具体编码 | 40 | 60 |
Code Review | 代码复审 | 20 | 10 |
Test | 测试(自我测试,修改代码,提交修改) | 15 | 15 |
Reporting | 报告 | 15 | 12 |
· | 测试报告 | 2 | 2 |
· | 计算工作量 | 15 | 10 |
· | 并提出过程改进计划 | 10 | 5 |