个人项目总结
个人项目的大部分设计都在上一篇博客中描述的比较清楚。
下面描述一下个人项目最终版本和上次描述的不同。
一、分数除零不再作为一个异常,而是融入到控制流中区判断。原因是随机生成的表达式中除0并不是稀有事件,为了更好的用户体验,最终的分数类为:
public class Fraction { private int numer; // numerator private int denom; // denominator public Fraction(int numer,int denom){ this.numer=numer; this.denom=denom; } public Fraction(int numer){ this.numer=numer; this.denom=1; } public int getNumer(){ return numer; } public int getDenom(){ return denom; } public void setNumer(int numer){ this.numer=numer; } public void setDenom(int denom){ this.denom=denom; } public String toString(){ simplfy(); if(denom==1) return numer+""; else{ if(denom<0){ denom*=-1; numer*=-1; } return numer+"/"+denom;} } public int gcd(int a,int b){ while(a%b!=0){ int temp=a%b; a=b; b=temp; } return b; } public int lcm(int a,int b){ return a*b/gcd(a,b); } public void simplfy(){ int a=gcd(numer,denom); numer/=a; denom/=a; } public Fraction add(Fraction op2){ int newdenom=lcm(denom,op2.denom); int newnumer=numer*newdenom/denom+op2.numer*newdenom/op2.denom; Fraction f=new Fraction(newnumer,newdenom); f.simplfy(); return f; } public Fraction minus(Fraction op2){ int newdenom=lcm(denom,op2.denom); int newnumer=numer*newdenom/denom-op2.numer*newdenom/op2.denom; Fraction f=new Fraction(newnumer,newdenom); f.simplfy(); return f; } public Fraction multi(Fraction op2){ Fraction f=new Fraction(numer*op2.numer,denom*op2.denom); f.simplfy(); return f; } public Fraction divide(Fraction op2) { Fraction f=new Fraction(numer*op2.denom,denom*op2.numer); f.simplfy(); return f; } public static void main(String[] args){ Fraction f=new Fraction(-4,6); f.simplfy(); System.out.println(f); } }
二、生成表达式的流程稍有改变。现在生成的表达式不会出现1+(3)这类含有无用括号的表达式,而且不会出现过多的连续左括号(以及其附带的结尾的过多连续右括号)
流程变为:
public static String generateExpression(int t){ String result=""; Random rand=new Random(System.currentTimeMillis()+t); int num=rand.nextInt(100); int time=rand.nextInt(10); int paircount=0; int a=rand.nextInt(2); //while(a==0) 开启则会有自由奔放的多重左括号 if(a==0) { result+='('; paircount++; a=rand.nextInt(2); } result+=Integer.toString(num); boolean ll=false; for(int i=0;i<time+2;i++){ int op=rand.nextInt(4); if(op==0)result+='+'; else if(op==1)result+='-'; else if(op==2)result+='*'; else result+='/'; //while(a==0) if(a==0 && i<time+1){ result+='('; paircount++; a=rand.nextInt(2); ll=true; } num=rand.nextInt(100); result+=Integer.toString(num); while(a!=0 && paircount>0 && !ll){ result+=')'; paircount--; a=rand.nextInt(2); } ll=false; } for(int i=paircount;i>0;i--) result+=')'; result+='='; return result; }
三、其他部分基本不变。增加了读写文件使生成的题目得以保存,增加了正确率统计,增加了一个简单的用户界面,更方便使用。
总结起来,在这个个人项目中,我收获的经验就是做好模块设计、逐步实现完善。
项目的时间分配上应该多花时间在设计和学习工具上。先设计好,才会有好的实现。而如果此时工具还没掌握就会效率低下,所以这方面的准备也要尽早完成。
结对编程初探
结对编程。我的理念是先结♂对,再编程。
我和我的partner现在还处在懵懂的合作状态。虽然我们之前就已经有过无数次的一起工作,但是归根结底还是分工的时候多,合作的内容少。
在和他一起工作的最开始阶段,我们首先深刻地结对分析问题。
在此次的结对编程中,我们首先遭遇的问题是实现语言的不同,我用了JAVA,他则是用了C++风格的C。最终我们agree on C++
之后的问题包括需求的较大幅度变化,包括从新引入了小数和负数,这使得我的用正则判别变得更加复杂甚至冗余,而且为了简化操作引入的分数类则需要大改,作为数这个基类的派生类来重新写。
好消息是我们的工程化思想和面向对象思想从来没有到过这个地步,现在是得到锻炼的好机会。
我认为结对编程要发挥出1+1>2的效果实现精简可靠的软件的过程中,每个人需要沉浸其中,合力又独立地完成任务,而不是做吹毛求疵者和拼写查错者。