zoukankan      html  css  js  c++  java
  • 软工网络15结对编程练习

    一、结对编程成员

    201521123003
    201521123005

    二、题目要求:

    一.现有代码分析

    (1)现有代码来源

    本次结对编程,我们选择网络14魏辉学长的程序代码进行改进。
    他的个人博客地址:http://www.cnblogs.com/weihui-01 ,他的源代码:https://coding.net/u/weh/p/software-testing/git
    (2)类图
    所选项目的类之间的关系如下:

    (3)项目的不足
    1、虽然项目有写当被除数为0的时候抛出异常,但是生成的题目就不可能存在这样的情况(下面会说到随机题目样式固定),异常代码如下:

    package qq;
    
    public class Yc extends Exception{
        public void Cs()
        {
            System.out.println("除数不为0");
        }
    }
    

    2、随机的低年级和高年级题目样式固定
    例如低年级随机题目并计算结果代码如下:

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

    3、题目计时不合理
    有关计时界面(拿低年级答题界面举例):

    运行时,做完一道题目后,按下题按键后并没有停止计时,直到按开始键才结束计时
    (5)逻辑泥球
    1、低年级的三种语言随机生成算式与计算答案的代码是重复的代码
    2、高年级的三种语言随机生成算式与计算答案的代码是重复的代码
    (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

    2、改进代码相关内容

    (1)完整代码
    改进代码的码云地址:https://gitee.com/yangxueying/pair_programming

    代码规范:

    (2)需求分析
    1、已有功能
    原有代码实现多种语言功能

    实现部分随机生成运算
    实现+、-、*、/计算
    2、改进及添加
    原有代码没有处理真分数计算的功能,没有做到随机题目的要求,增加括号操作符乘方,减少重复题目的功能
    (3)设计分析

    类图:

    (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)关键模块消耗最大的函数
    主要是是个调用的包消耗大。

    三、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

    四、小结感受

    本次结对编程不能说是第一次,因为之前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
    参照“效能测试,分析,改进,再效能测试”的流程,找出关键模块消耗最大的函数,是否存在改进?

  • 相关阅读:
    添加/删除windows组件里面没有IIS选项
    安装好 SQL Server 2008,发现不能新建数据库
    Professional C++读书笔记01
    Professional C++读书笔记04
    Professional C++读书笔记05
    Professional C++读书笔记03
    coursera_intro_to_python_notebook_1
    Professional C++读书笔记02
    Professional C++读书笔记06
    silverlight中创建自定义的Tabcontrol控件
  • 原文地址:https://www.cnblogs.com/yangxy/p/8644479.html
Copyright © 2011-2022 走看看