結對編程-四則運算(二)


寫在前面

經歷了兩周的結對編程,我和王旌含在相互幫助中學到了不少,進步了不少。但我們認為這還不是我們理想中結對編程—我們起初當定義過自己在結對編程中角色,但在結對過程中卻發生了改變,就像是在玩蹺蹺板,一個胖子和一個瘦子一起玩必定是索然無味的。唯有體重相差不大的人才能體會。有時候我們都想當瘦子,有時候我又成了大胖子,不斷催促他個瘦子。對此我們詢問了班上其他的結對對象,發現他們也陷入了此類問題,也許他們的編程速度比我們快,但其實並沒有體現出結對編程,只是個人寫個人的類,做自己的單元測試,自己修改,到最后只是將自己的類的作用解釋給同伴。因為我們兩人的能力不同,為了都能在結對編程中體現價值,在這周我們做了以下決定:

並不是蹺蹺板胖瘦不同的人就不能玩了,我們決定不再關注兩人的編程能力是否一樣。
我們決定不是所有的任務都采用結對編程的模式。
對於程序中的重要類我們決定不斷“復審”,我們開始“強迫”兩人交流,開始根據能力的不同進行角色分工和互換

代碼重構

  • 這周我們剛的第一件事就是一起將我們生成題目的類進行升級重構
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個小時在寫各自的代碼,之所以是各自的代碼(無論復雜簡單)是因為我們回頭反思發現在做具體的需求分析,具體設計是沒能合理安排,在一開始階段沒能達成統一,導致我寫代碼他不懂,他的代碼我不知怎么用,我們之間沒有復審與重構,更沒有角色的交換;其次,伙伴對於單元測試能力的欠缺導致在測試上也花了不少時間,可能比統計的多。總之這次的結對效果很是不理想,設計的程序不是很能說明問題,因為一個人做也能做出來。我們跟很多結對者有過交流,發現我們的結對編程還是有一定效果的,這給了我們很大信心。說句實話話,我並不是很贊成結對編程,因為相比結對,我更喜歡一個人編代碼,因為在某些問題上我不需要跟別人解釋。但既然結對編程了,我們是真心想要做好,拭目以待。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM