201521123003
201521123005
html
(1)现有代码来源java
本次结对编程,咱们选择网络14魏辉学长的程序代码进行改进。
他的我的博客地址:http://www.cnblogs.com/weihui-01 ,他的源代码:https://coding.net/u/weh/p/software-testing/git
(2)类图
所选项目的类之间的关系以下:
(3)项目的不足
一、虽然项目有写当被除数为0的时候抛出异常,可是生成的题目就不可能存在这样的状况(下面会说到随机题目样式固定),异常代码以下:git
package qq; public class Yc extends Exception{ public void Cs() { System.out.println("除数不为0"); } }
二、随机的低年级和高年级题目样式固定
例如低年级随机题目并计算结果代码以下:程序员
char a[]={'+','-','×','÷'}; int b=(int)(Math.random()*4); int c=(int)(Math.random()*100); int d=(int)(Math.random()*99+1);//排除了被除数为0的状况 int f=(int)(Math.random()*100); if(a[b]==a[0]) { T2.setText(c+String.valueOf(a[b])+f+"/"+d); sum=c+(float)f/d; } else if(a[b]==a[1]) { T2.setText(c+String.valueOf(a[b])+f+"/"+d); sum=c-(float)f/d; } else if(a[b]==a[2]) { T2.setText(c+String.valueOf(a[b])+"("+f+"/"+d+")"); sum=c*((float)f/d); } else if(a[b]==a[3]) { T2.setText(c+String.valueOf(a[b])+"("+f+"/"+d+")"); sum=(float)c/((float)f/d); }
三、题目计时不合理
有关计时界面(拿低年级答题界面举例):
运行时,作完一道题目后,按下题按键后并无中止计时,直到按开始键才结束计时
(5)逻辑泥球
一、低年级的三种语言随机生成算式与计算答案的代码是重复的代码
二、高年级的三种语言随机生成算式与计算答案的代码是重复的代码
(6)原项目中测试用例覆盖
测试用例所测的功能是检查四则运算计算答案的正确性编程
(7)原题目要求
http://www.cnblogs.com/happyzm/p/6472120.html
http://www.cnblogs.com/happyzm/p/6509116.html
http://www.cnblogs.com/happyzm/p/6558307.html数组
(1)完整代码
改进代码的码云地址:https://gitee.com/yangxueying/pair_programming
网络
代码规范:
app
(2)需求分析
一、已有功能
原有代码实现多种语言功能
实现部分随机生成运算
实现+、-、*、/计算
二、改进及添加
原有代码没有处理真分数计算的功能,没有作到随机题目的要求,增长括号操做符乘方,减小重复题目的功能
(3)设计分析
类图:
dom
(4)代码实现
1.支持括号优先级运算和乘方计算函数
package Function; import java.util.Stack; public class Result { private static Stack<String> num = new Stack<String>();//存后缀表达式 private static Stack<String> sign = new Stack<String>();//存入符号 private static Stack<Double> result = new Stack<Double>();//放结果 public static void getGroup(String line){//讲字符串转换为后缀表达式 for(int i=0; i<line.length(); i++){ char c = line.charAt(i); if((int)c>=48 && (int)c<=57){//当遇到数字的时候,判断是否是多位数,而后在push进num int j = i+1; while(j<line.length() && (line.charAt(j)>=48 && line.charAt(j)<=57)){ j++; } num.push(line.substring(i, j)); i = j-1; }else if(c == '('){//遇到左括号直接存进num sign.push(String.valueOf(c)); }else if(c == ')'){//遇到右括号从sign中pop栈顶元素push到num知道遇到'(',而后再pop掉'(' while(!sign.peek().equals("(")){ num.push(sign.pop()); } sign.pop(); }else{ int n = 0; if(!sign.empty()){//若是sign中没有元素,直接令n = 0 n = getNum(sign.peek().charAt(0)); } int m = getNum(c); if(m >= n){//若是当前元素的运算级别比栈顶元素运算级别要高,就直接push进sign sign.push(String.valueOf(c)); }else{ while(m < n){//若是当前运算运算级别比sign栈顶元素运算级别要低,就将sign栈顶元素pop而且push进num,知道不符合条件 num.push(sign.pop());//输入例子2*3+6/3的时候,这里一直报错 if(!sign.empty()){ n = getNum(sign.peek().charAt(0)); }else{ n = 0; } } sign.push(String.valueOf(c)); } } } while(!sign.empty()){ num.push(sign.pop()); } } private static int getNum(char c){ int n = 0; switch(c){ case '+': case '-': n = 1; break; case '*': case '^': case '/': n = 2; break; } return n; } private static void getResult(){//讲获得的后缀表达式反转遍历,遇到数字就加入result,遇到符号就从result中取出两个数进行运算而后将结果加入result Stack<String> t = new Stack<String>(); while(!num.empty()){ t.push(num.pop()); } String str = t.pop(); while(str != null){ if(str.equals("+") || str.equals("-") || str.equals("*") || str.equals("/")||str.equals("^")){ double n = result.pop(); double m = result.pop(); double num = 0; if(str.equals("+")) num = m+n; if(str.equals("-")) num = m-n; if(str.equals("*")) num = m*n; if(str.equals("/")) num = m/n; if(str.equals("^")) num = Math.pow(m, n); result.push(num); }else{ result.push(Double.parseDouble(str)); } if(!t.empty()){ str = t.pop(); }else{ str = null; } } } public Double getAnswer(String timu) { getGroup(timu); getResult(); return result.peek(); } }
2.程序生成的算式不重复
(如下代码可能没法达到预期,咱们也明白就是交换+号两边的数,可是实现很复杂,后来听了嘉廉同窗的方法,能够用树解决,以为本身仍是要多努力啊!)
package Function; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.Queue; import java.util.Stack; public class GetChongFu { public static List<String> getChoufu(String timu) { List<String> chongti = new ArrayList<>(); if(timu.contains("(")) { List<String> num = new ArrayList<>(); List<String> fuhao = new ArrayList<>(); for(int i=0; i<timu.length(); i++) { char c = timu.charAt(i); if((int)c>=48 && (int)c<=57){//当遇到数字的时候,判断是否是多位数,而后在push进num int j = i+1; while(j<timu.length() && (timu.charAt(j)>=48 && timu.charAt(j)<=57)){ j++; } num.add(timu.substring(i, j)); } else { fuhao.add(String.valueOf(c)); fuhao.add(String.valueOf(i)); } } int cishu=0; int[] n; n=new int[3]; for(int i=0;i<fuhao.size();i++) { if(fuhao.get(i).equals("+")) { cishu++; if(i==0) { String str=num.get(1)+"+"+num.get(0); for(int j=2;j<fuhao.size();j++) { str=fuhao.get(j)+num.get(j+1); if(fuhao.get(i).equals("+")) j++; } chongti.add(str); } if(cishu==2) { n[1]=Integer.valueOf(num.get(i+1)); chongti.add(timu.substring(0,n[0]-1)+"+"+timu.substring(n[1]+1,timu.length())+"+"+timu.substring(n[0]+1, n[1]-1)); } if(cishu==3) { n[2]=Integer.valueOf(num.get(i+1)); chongti.add(timu.substring(0,n[1]-1)+"+"+timu.substring(n[2]+1,timu.length())+"+"+timu.substring(n[1]+1, n[2]-1)); chongti.add(timu.substring(0,n[0]-1)+"+"+timu.substring(n[2]+1,timu.length())+"+"+timu.substring(n[0]+1, n[2]-1)); } n[0]=Integer.valueOf(num.get(i+1)); chongti.add(timu.substring(n[0]+1,timu.length())+"+"+timu.substring(0, n[0]-1)); } else { cishu=0; if(fuhao.get(i).equals("*")) { if(i==0) { int d1=Integer.valueOf(num.get(i)); int d2=Integer.valueOf(num.get(i+1)); if(i+1<fuhao.size()) { chongti.add(timu.substring(d1+1,d2-1)+"*"+timu.substring(0,d1-1)+timu.substring(d2, timu.length())); } else chongti.add(timu.substring(d1+1,d2-1)+"*"+timu.substring(0,d1-1)); } else if(i==(fuhao.size()-1)) { int d3=Integer.valueOf(num.get(i-1)); String s=timu.substring(0,d3)+num.get(i/2+1)+"*"+num.get(i/2); chongti.add(s); } else { int d1=Integer.valueOf(num.get(i-1)); int d2=Integer.valueOf(num.get(i)); int d3=Integer.valueOf(num.get(i+1)); String s=timu.substring(0,d1)+num.get(i/2+1)+"*"+num.get(i/2)+timu.substring(d3, timu.length()); } } } i++; } } return chongti; } }
3.随机生成算式
package Function; import java.util.Random; public class RandomTimu { public static String DnjcalStringCreate(int r){ char []c={'+','-','*','/'};//操做符数组 Random random=new Random(); StringBuffer str=new StringBuffer(); int n= random.nextInt(3)+1; int num=random.nextInt(r-1)+1; str.append(num); for (int i = 0; i <n ; i++) {//在1到3范围内随机个数的运算符 char c2=c[(int)(c.length* java.lang.Math.random())];//生成随机操做符 int num2=random.nextInt(r-1)+1;//生成大于0小于r的天然数 str.append(c2); str.append(num2); } return str.toString(); } public static String GnjcalStringCreate(int r){ char []c={'+','-','*','/','^'};//操做符数组 Random random=new Random(); String timustr=""; int n= random.nextInt(3)+1; int num=random.nextInt(r-1)+1; timustr=timustr+num; for (int i = 0; i <n ; i++) {//在1到3范围内随机个数的运算符 char c2=c[(int)(c.length* java.lang.Math.random())];//生成随机操做符 int num2=random.nextInt(r-1);//生成大于0小于r的天然数 if(c2=='^') { num2=random.nextInt(3); } if(c2=='/') { if(num2==0) num2=random.nextInt(r-1)+1; } timustr=timustr+c2; timustr=timustr+num2; if(random.nextInt(10)==0&&i<n-1) { timustr="("+timustr+")"; } } return timustr; } }
4.支持结果能够存在分数
if(answer.contains("/")) { int length=answer.length(); for(int i=0; i<length; i++){ char c = answer.charAt(i); if((int)c>=48 && (int)c<=57) {//当遇到数字的时候,判断是否是多位数 int j = i+1; while(j<length && (answer.charAt(j)>=48 && answer.charAt(j)<=57)){ j++; } floatanswer=Float.parseFloat(answer.substring(i, j)); i = j-1; } else { int j = i+1; while(j<length && (answer.charAt(j)>=48 && answer.charAt(j)<=57)){ j++; } float a1=Float.parseFloat(answer.substring(i+1, j)); floatanswer=floatanswer/a1; break; } } answer=String.valueOf(floatanswer); if(Float.parseFloat(str)-floatanswer<0.00001) { T4.setText("恭喜你!答对了!"); dadui++; T5.setText(String.valueOf(dadui)); } else { T4.setText("真遗憾!答错了!正确答案是"+Float.parseFloat(str)); dacuo++; T6.setText(String.valueOf(dacuo)); } }
(5)回归测试的用例
package Function; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; public class ResultTest { @Before public void setUp() throws Exception { } @Test public void testGetAnswer() { //原项目测试用例 assertEquals(3.0, Result.getAnswer("1+4/2"),0.0); assertEquals(0.0, Result.getAnswer("1-1/1"),0.0); assertEquals(1.0, Result.getAnswer("1*1/1"),0.0); assertEquals(1.0, Result.getAnswer("1/1/1"),0.0); assertEquals(3.0, Result.getAnswer("1+1/1+1/1"),0.0); assertEquals(1.0, Result.getAnswer("1+1/1-1/1"),0.0); //新增功能测试用例 assertEquals(6.0, Result.getAnswer("2*3"),0.0); assertEquals(-1, Result.getAnswer("2-3"),0.0); assertEquals(0.67, Result.getAnswer("2/3"),0.01); assertEquals(8.0, Result.getAnswer("2^3"),0.0); assertEquals(14.0, Result.getAnswer("2+3*4"),0.0); assertEquals(4.0, Result.getAnswer("2+3+(5-6)"),0.0); assertEquals(25.0, Result.getAnswer("(2+3)^2"),0.0); assertEquals(15.0, Result.getAnswer("((2+3)^2+5)/2"),0.0); } }
(6)项目覆盖
(7)效能分析结果
(8)关键模块消耗最大的函数
主要是是个调用的包消耗大。
PSP2.1 | 我的开发流程 | 预估耗费时间(分钟) | 实际耗费时间(分钟) |
---|---|---|---|
Planning | 计划 | 10 | 30 |
· Estimate | 明确需求和其余相关因素,估计每一个阶段的时间成本 | 10 | 30 |
Development | 开发 | 720 | 900 |
· Analysis | 需求分析 (包括学习新技术) | 60 | 90 |
· Design Spec | 生成设计文档 | 10 | 30 |
· Design Review | 设计复审 | 10 | 20 |
· Coding Standard | 代码规范 | 30 | 35 |
· Design | 具体设计 | 90 | 120 |
· Coding | 具体编码 | 400 | 365 |
· Code Review | 代码复审 | 60 | 120 |
· Test | 测试(自我测试,修改代码,提交修改) | 60 | 120 |
Reporting | 报告 | 100 | 170 |
· | 测试报告 | 40 | 70 |
· | 计算工做量 | 20 | 30 |
· | 并提出过程改进计划 | 40 | 70 |
本次结对编程不能说是第一次,由于以前java做业也有结对编程的任务。可是以前的结对编程是靠彼此默契,如今此次结对编程相对有方法。经过本次结对编程学会更好的规范代码,学会预估等等。我认为结对编程真的可以带来1+1>2的效果。结对编程写代码时,想法能够及时交流,有错误时能够站在不一样的角度去解决。相对于本身编程,结对编程的效率更高。
参考 重构-靠谱程序员的必备技能:https://mp.weixin.qq.com/s/23a8BY_fP168GWLrGLJzrw JUnit单元测试:http://www.cnblogs.com/happyzm/p/6482886.html Java覆盖率统计:http://www.cnblogs.com/happyzm/p/6530384.html 效能分析工具:http://www.oschina.net/p/jprofiler ,使用方法: http://www.cnblogs.com/bjlhx/p/6668888.html 参考教材P29-34 参照“效能测试,分析,改进,再效能测试”的流程,找出关键模块消耗最大的函数,是否存在改进?