结对编程项目之队友个人项目优缺点
子曰:三人行,必有我师焉;择其善者而从之,其不善者而改之。
虽然她给我找出bug时让我有点挫败感(因为当我费尽九牛二虎之力写完代码,实现要求中所有功能的时候,我感觉自己超级厉害,代码写得也很完美了),但是不得不承认,她说的都是对的。在需求分析中,我对要求有些误解,在代码实现中,又有些细节和特例没有考虑到。在她提出之后,我对自己的代码进行了完善。
她的代码有很多值得我学习的地方,但同样也有考虑不周的地方,我想,这大概就是结对编程的意义吧。
对方代码的思路
放个不是很规范的流程图来帮助理解吧
这个流程图是队友画的,我个人觉这是一个很好的习惯,通过这个流程图可以清楚的看到队友代码的思路。
优点
1、括号考虑周全。在我的代码里,只考虑了一个题目中生成一个括号的情况。而她的代码,由于括号的位置和括号是否生成都是随机的,因此可以生成多个括号。这里以小学卷子的生成为例,附上代码进行详述。
for(k = 0; k < num; k++) { //题目数
int num1 = rand()%4+2; //操作数个数,小学的操作数一定是2-5个
int bracket = 0;//判断生成左括号或右括号,为0时生成左括号然后立刻置1表明下一次生成右括号
bool flag = 0;//排除一个括号将所有操作数都括住的这种特殊情况
if(rand()%2==1) {//先处理第一个数
flag = 1;
result[k]+="(";
bracket = 1;
operand = rand()%100+1; //生成操作数1~100
sprintf(temp,"%d",operand); //操作数转为字符串
result[k] += temp;
} else {
operand = rand()%100+1; //生成操作数1~100
sprintf(temp,"%d",operand); //操作数转为字符串
result[k] += temp;
}
for(int i = 2; i < num1; i++) {
if(rand()%2==1) {
if(bracket == 0) {
Oper = rand()%4; //选择+,-,*,/
result[k] += Operator1[Oper];
result[k] += "("; //生成"("
operand = rand()%100+1; //生成操作数1~100
sprintf(temp,"%d",operand); //操作数转为字符串
result[k] += temp;
bracket = 1;
} else {
if(flag == 1) {
flag = 0;
}
Oper = rand()%4; //选择+,-,*,/
result[k] += Operator1[Oper];
operand = rand()%100+1; //生成操作数1~100
sprintf(temp,"%d",operand); //操作数转为字符串
result[k] += temp;
result[k] += ")";
bracket = 0;
}
} else {
Oper = rand()%4; //选择+,-,*,/
result[k] += Operator1[Oper];
operand = rand()%100+1; //生成操作数1~100
sprintf(temp,"%d",operand); //操作数转为字符串
result[k] += temp;
}
}
//对最后一个数的处理
if(flag==1) {
if(num1==2) {
Oper = rand()%4; //选择+,-,*,/
result[k] += Operator1[Oper];
operand = rand()%100+1;
sprintf(temp,"%d",operand);
result[k] += temp;
result[k] += ")";
Oper = rand()%4; //选择+,-,*,/
result[k] += Operator1[Oper];
operand = rand()%100+1;
sprintf(temp,"%d",operand);
result[k] += temp;
} else {
Oper = rand()%4; //选择+,-,*,/
result[k] += Operator1[Oper];
operand = rand()%100+1;
sprintf(temp,"%d",operand);
result[k] += temp;
result[k]+=")";
}
} else {
if(bracket == 1) {
Oper = rand()%4; //选择+,-,*,/
result[k] += Operator1[Oper];
operand = rand()%100+1; //生成操作数1~100
sprintf(temp,"%d",operand); //操作数转为字符串
result[k] += temp;
result[k]+=")";
} else {
Oper = rand()%4; //选择+,-,*,/
result[k] += Operator1[Oper];
operand = rand()%100+1; //生成操作数1~100
sprintf(temp,"%d",operand); //操作数转为字符串
result[k] += temp;
}
}
if(!Check(result[k],name,state)) {
k=k-1;
}
}
这段代码很长,但是如果只看生成括号的那一部分其实很简单,比较复杂的是后面括号和操作数的结合,由于情况很多,她是按照情况分类来写的,所以会存在一些问题(说实话,我觉得操作数这一块我的处理稍微简单一些,可以和她的生成括号相结合可能就比较简洁了hhhh)。
2、程序在需要的时候自动生成文件夹。我是在放代码的文件夹里手动创建的文件夹,而不是由代码生成。这样子其实是有些取巧的,而且实用性不高,而队友的代码就很好,在没有文件夹创建文件夹,而文件夹存在的时候直接访问,无需创建文件夹了。
string path = "D:\\\\";
path+=name;
if(access(path.c_str(), 0) != 0) {
mkdir(path.c_str());
}
if(state==1) {
path+="\\\\小学\\\\";
}
if(state==2) {
path+="\\\\初中\\\\";
}
if(state==3) {
path+="\\\\高中\\\\";
}
if(access(path.c_str(), 0) != 0) {
mkdir(path.c_str());
}
SYSTEMTIME sys;
GetLocalTime(&sys);
char tmp[64] ;
sprintf(tmp,"%4d-%02d-%02d-%02d-%02d-%02d",sys.wYear,sys.wMonth,sys.wDay,sys.wHour,sys.wMinute,sys.wSecond);//以年月日时分秒对文件命名
path += tmp;
path += ".txt";
ofstream outfile;
outfile.open(path.c_str());
if(!outfile) {
cout<<"Unable to open outfile";
exit(1);
}
for(int i=1; i<=num; i++) {
outfile<<i<<"、"<<result[i-1]<<endl;
outfile<<endl;
}
3、思路清晰,函数的使用让代码结构清楚,各个模块的实现互不影响,但是模块与模块之间又紧密联系。
4、代码格式规范,注释简洁明了,变量名也一目了然。
缺点
1、忽略了一些小细节,例如输入-1时直接退出而不是重新登录,没有检查题目数目的有效范围,即当输入数字不在[10,30]之间时,也会生成卷子。
2、她的程序是先检查密码输入,所以当账号输入错误时程序就卡住了,无论输入什么都没有反应了。就这一点,我觉得还是应该先检查账号再检查密码,这样比较符合登录的习惯。
3、生成卷子的代码过于长,她的代码是分别处理小学、初中、高中的卷子,没有考虑代码重用。