写在前面
经历了两周的结对编程,我和王旌含在相互帮助中学到了不少,进步了不少。但我们认为这还不是我们理想中结对编程—我们起初当定义过自己在结对编程中角色,但在结对过程中却发生了改变,就像是在玩跷跷板,一个胖子和一个瘦子一起玩必定是索然无味的。唯有体重相差不大的人才能体会。有时候我们都想当瘦子,有时候我又成了大胖子,不断催促他个瘦子。对此我们询问了班上其他的结对对象,发现他们也陷入了此类问题,也许他们的编程速度比我们快,但其实并没有体现出结对编程,只是个人写个人的类,做自己的单元测试,自己修改,到最后只是将自己的类的作用解释给同伴。因为我们两人的能力不同,为了都能在结对编程中体现价值,在这周我们做了以下决定:
并不是跷跷板胖瘦不同的人就不能玩了,我们决定不再关注两人的编程能力是否一样。
我们决定不是所有的任务都采用结对编程的模式。
对于程序中的重要类我们决定不断“复审”,我们开始“强迫”两人交流,开始根据能力的不同进行角色分工和互换
代码重构
- 这周我们刚的第一件事就是一起将我们生成题目的类进行升级重构
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个小时在写各自的代码,之所以是各自的代码(无论复杂简单)是因为我们回头反思发现在做具体的需求分析,具体设计是没能合理安排,在一开始阶段没能达成统一,导致我写代码他不懂,他的代码我不知怎么用,我们之间没有复审与重构,更没有角色的交换;其次,伙伴对于单元测试能力的欠缺导致在测试上也花了不少时间,可能比统计的多。总之这次的结对效果很是不理想,设计的程序不是很能说明问题,因为一个人做也能做出来。我们跟很多结对者有过交流,发现我们的结对编程还是有一定效果的,这给了我们很大信心。说句实话话,我并不是很赞成结对编程,因为相比结对,我更喜欢一个人编代码,因为在某些问题上我不需要跟别人解释。但既然结对编程了,我们是真心想要做好,拭目以待。