结对编程-四则运算(二)

写在前面

经历了两周的结对编程,我和王旌含在相互帮助中学到了不少,进步了不少。但我们认为这还不是我们理想中结对编程—我们起初当定义过自己在结对编程中角色,但在结对过程中却发生了改变,就像是在玩跷跷板,一个胖子和一个瘦子一起玩必定是索然无味的。唯有体重相差不大的人才能体会。有时候我们都想当瘦子,有时候我又成了大胖子,不断催促他个瘦子。对此我们询问了班上其他的结对对象,发现他们也陷入了此类问题,也许他们的编程速度比我们快,但其实并没有体现出结对编程,只是个人写个人的类,做自己的单元测试,自己修改,到最后只是将自己的类的作用解释给同伴。因为我们两人的能力不同,为了都能在结对编程中体现价值,在这周我们做了以下决定:

并不是跷跷板胖瘦不同的人就不能玩了,我们决定不再关注两人的编程能力是否一样。
我们决定不是所有的任务都采用结对编程的模式。
对于程序中的重要类我们决定不断“复审”,我们开始“强迫”两人交流,开始根据能力的不同进行角色分工和互换

代码重构

  • 这周我们刚的第一件事就是一起将我们生成题目的类进行升级重构
public class Project {
    Random in = new Random();
    int a = in.nextInt(10)+1;
    int b = in.nextInt(10)+1;
    int c = in.nextInt(10)+1;
    int num = in.nextInt(4);
    int num2 = in.nextInt(4);
    String [] Operator = {"*","+","-","/"};
    public String HighPro(){
        int a = in.nextInt(6)+5;
        int b = 2*a+1;

        StringBuilder result = new StringBuilder(100);
        for (int i = 0;i<b;i++){
            int num3 = in.nextInt(10);
            int num4 = in.nextInt(4);

            if (i%2==0){
                result.append(num3);
            }
            if(i%2!=0){
                result.append(Operator[num4]);
            }
        }
        return String.valueOf(result);
    }
}

这是我起初编写的生成题目的代码,她有以下个问题

  • 没有排除除数为零的情况
  • 没有添加函数的方法
  • 代码不规范不整洁

对此我们改变了生成题目的方式

    /*例子:1+(2+3)*4+5
    将此类题目分成三部分
    前部:1+
    中部:(2+3)
    后部:*4+5
    最后将几个部分结合
    */

这是之后的代码

import java.util.Random;

/**
 * Created by asus on 2017/5/18.
 */
public class NewProject extends SetNum{
    public String Front(){
        String result;
        switch (getC()){

            case 0:
                result = getA()+Operator[getB()];

                break;
            case 1:
                result = getA()+Operator[getB()]+getA()+Operator[getB()];

                break;
            default:
                result = getA()+Operator[getB()]+getA()+Operator[getB()]+getA()+Operator[getB()];
        }
        return result;
    }
    public String Middle(){
        String result;
        switch (getC()){
            case 0:
                result = getA()+"";
                break;
            case 1:
                result ="("+getA()+Operator[getB()]+getA()+")";
                break;
                default:
                    result = "("+getA()+Operator[getB()]+"("+getA()+Operator[getB()]+getA()+")"+Operator[getB()]+getA()+")";
        }
        return result;
    }
    public String End(){
        String result;
        switch (getC()){
            case 0:
                result = Operator[getB()]+getA();
                break;
            case 1:
                result = Operator[getB()]+getA()+Operator[getB()]+getA();
                break;
                default:
                    result =  Operator[getB()]+getA()+Operator[getB()]+getA()+Operator[getB()]+getA();
        }
        return result;
    }
    public String Allpart(){
        String result;
        switch (getC()){
            case 0:
                result = Front()+Middle();
                break;
            case 1:
                result = Middle()+Front();
                default:
                    result = Front()+Middle()+End();
        }
        return result;
    }
    public String JudgeAllpart(){
        String result =Allpart();
        for(int i = 0;i<result.length();i++){
            if ((result.charAt(i)=='/')&&(result.charAt(i+1)=='0')){
                result = Allpart();
            }
        }
        return result;
    }

}

import java.util.Random;

/**
 * Created by asus on 2017/5/18.
 */
public class SetNum {
    Random in = new Random();
    int a;
    int b;
    int c;

    public int getC() {
        setC();
        return c;
    }

    public void setC() {
        this.c = in.nextInt(3);
    }

    String [] Operator = {"+","-","*","/"};

    public int getB() {
        setB();
        return b;
    }

    public void setB() {
        this.b = in.nextInt(4);
    }

    public void setA() {
        this.a = in.nextInt(10);
    }

    public int getA() {
        setA();
        return a;
    }
}

当然以上代码是我们对其重构后的结果,中间代码因为重构了没有保留源
具体重构如下:

  • 原代码并没有gettrt and setter而是每次都要使用随机数生成造成代码重复很多
    于是我们将其添加gettrt and setter,为了是每次调用都随机产生数,于是在get中在调用set
  • 我们考虑的其他类的编写中都会用到相同范围的随机数,于是定义SetNum类来作为父类,要使用的子类只需要继承即可,避免代码重复
  • 第二件事情是我们继续上周未能完成的Junit测试
    我们主要测试的是修改后的postfix类是否能继续胜任她的工作
    public void testCount() throws Exception {
    //TODO: Test goes here...
    String line;
    BufferedReader rdr = new BufferedReader(new FileReader("testdata.txt"));
    while ((line = rdr.readLine()) != null) {
        if (line.startsWith("#")) {
            continue;
        }
        StringTokenizer st = new StringTokenizer(line);
        if (!st.hasMoreTokens()) {
            continue;
        }
        String val = st.nextToken();
        String expected = val;

        LinkedList<String> argument_list = new LinkedList();
        while (st.hasMoreTokens()) {
            argument_list.add(st.nextToken());
        }
        Postfix a = new Postfix();
        a.transferToPostfix(argument_list);
        assertEquals(expected, a.transferToPostfix(argument_list));;
    }
}

因为用到大量测试数据,我们考虑用到一个独立的数据文件来储存这些测试数据,然后让单元测试读取该文件

数据文件的格式是:第一个数字是想要运算的结果,后面是所要运算的题目,用空格隔开;
用井号#表示所在行是注释
自动忽略空行


这是我们的成果

我的感悟

这次的结对编程我们学到了不少,代码在两个人的不断重构和复审之间变得更完美,但也有不好的地方就是当结对人员变得懒散时你不得不督促他。我认为这是不好的,结对编程要求投入,你尽可以偷懒,因为你的工作伙伴可以完成,但这不是我想要的结对编程,因为我们从中得不到任何好处,不会提高效率,更不会有所成长。

当这个统计结果出来之后是难以置信的,在具体编码的用时上我们两人花了将近10个小时在写各自的代码,之所以是各自的代码(无论复杂简单)是因为我们回头反思发现在做具体的需求分析,具体设计是没能合理安排,在一开始阶段没能达成统一,导致我写代码他不懂,他的代码我不知怎么用,我们之间没有复审与重构,更没有角色的交换;其次,伙伴对于单元测试能力的欠缺导致在测试上也花了不少时间,可能比统计的多。总之这次的结对效果很是不理想,设计的程序不是很能说明问题,因为一个人做也能做出来。我们跟很多结对者有过交流,发现我们的结对编程还是有一定效果的,这给了我们很大信心。说句实话话,我并不是很赞成结对编程,因为相比结对,我更喜欢一个人编代码,因为在某些问题上我不需要跟别人解释。但既然结对编程了,我们是真心想要做好,拭目以待。

posted @ 2017-05-21 20:17  Wb同学在此  阅读(220)  评论(14编辑  收藏  举报