zoukankan      html  css  js  c++  java
  • 软工网络15结对编程(201521123003 董美凤)

    1.项目成员

    董美凤:201521123003
    杨雪莹:201521123005
    结对编程码云地址:https://gitee.com/yangxueying/pair_programming
    原源代码地址:https://coding.net/u/weh/p/software-testing/git

    2.需求分析

    现有代码主要实现了高年级和低年级加减乘除四则运算,语言选择,选择题数,计算答题对错的数量。
    分析原有代码,发现以下问题:

    • 所出题目的类型单一,只有三个数字和两个操作符的形式,如a+b-c
    • 计算答案的部分也只有按照这种题目类型作出相应的计算,如果所出的题目变成其他形式,就计算不出结果,局限性较大
    • 没有对重复题目作出判断
    • 高低年级的题目难度差不多,没有作出明显区分
    • 源代码的计时模块存在一定问题,有时候计时时间到了会停止做题,有时候又无限计时
    • 代码重复量高,同样的代码出现了好几次,出现逻辑泥球,如下图低年级的三种语言的代码是重复的,高年级的三种语言也代码是重复的,界面类也是

    作出的修改:

    • 重构了随机出题的模块,使得出题类型增加,有更多变换形式
    • 当输入答案是分数时,无法判断答案正确与否
    • 将计算答案的部分做了重构,采用后缀表达式来计算最终答案,这样写一个方法,同样适用于高年级和低年级的答案计算
    • 优化了计时模块,使每道题的做题时间超时会提示退出

    新加入的功能:

    • 增加括号操作符
    • 出题过程中减少重复题目
    • 高年级的出题类型增加了乘方的形式
    • 当输入答案是分数或者小数形式时,都可判断答案是否正确

    3.程序设计

    思维导图

    类图:

    4.代码展示

    括号优先级运算以及增加乘方运算,运用后缀表达式,具体代码如下:

    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 == '('){
    	                sign.push(String.valueOf(c));
    	            }else if(c == ')'){
    	                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){
    	                        num.push(sign.pop());
    	                        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();
    	}
    	
    }
    

    随机生成题目代码:

    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)+1;//生成大于0小于r的自然数
                if(c2=='^')
                {
                	num2=random.nextInt(3);
                }
                timustr=timustr+c2;
                timustr=timustr+num2;
                if(random.nextInt(10)==0&&i<n-1)
                {
                	timustr="("+timustr+")";
                }
            }
            return timustr;
        }
    }
    

    减少题目重复关键代码:

    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;
    	}
    }
    

    回归测试:
    由于我们重构了计算答案这部分的代码,所以对这部分进行了单元测试。

    覆盖率测试:



    效能分析:



    5.程序运行


    乘方计算

    分数计算

    6.小结感受

    经过两周的结对编程,结对编程在一定程度上是能达到1+1>2的效果,特别是在编写代码的过程中,一个功能如何实现或者bug的修改的时候,有时候自己做的时候容易陷入一个死胡同(有时候眼瞎,明显的错误都看不见),结对编程的时候就不一样了,两个人找起bug来速度明显快多了。而且在代码重构时,每个人对于功能的实现理解和想法都不同,所以两个人一起想可以互相弥补双方的不足,互相学习。


    码云提交截图:



    7.PSP

    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
  • 相关阅读:
    [原创] 扩展jquery-treegrid插件, 实现勾选功能和全删按钮.
    [原创]多版本Java环境变量的配置
    [转]Redmine 配置163邮箱
    [转] --- Error: “A field or property with the name was not found on the selected data source” get only on server
    服务器控件中使用<%#...>, JS和html控件中使用<%=...>
    【字源大挪移—读书笔记】 第三部分:字尾
    【字源大挪移—读书笔记】 第二部分:字根
    使用WebClient 或者 HttpWebRequest均报:"The Remote name can't be solved"
    【字源大挪移—读书笔记】 第一部分:字首
    【英语魔法俱乐部——读书笔记】 3 高级句型-简化从句&倒装句(Reduced Clauses、Inverted Sentences) 【完结】
  • 原文地址:https://www.cnblogs.com/dongmf/p/8645487.html
Copyright © 2011-2022 走看看