面向对象程序设计题目集一至三技术总结
面向对象程序设计的前三周的题目集整体难度不高,题目集一主要考察java基础语法,以及编写程序时逻辑思维能力,题目量较多但不难,也没有涉及到类设计部分。题目集二相较于题目集一题量减少,但难度有所提高,但还是难度不大,主要考察了方法在类中的使用。题目集三相对于前两个题目集体量少但难度高,主要是考察类间设计,以及正则表达式的使用。
下面是使用SourceMonitor对代码进行圈复杂度分析
题目集一的7-8,是判断三角形类型的题目,需要用到大量的if语句,而采用大量的if语句便会使代码的圈复杂度较大,使代码的质量变差,下图是复杂度分析

可见代码的最大复杂度已经到了16,远超于10,代码质量较差,究其原因为使用了大量的if语句并且嵌套,核心代码见下图

在课上老师进行圈复杂度讲解演示时,一开始采用了if语句,圈复杂度较大,后面改成了switch语句,圈复杂度减少,原因是switch采用的是匹配模式,而不是逐个判断。所以这里的改进思路为将if语句改成switch语句,可以在switch后的表达式设置为ture,而后每个case后的表达式采用条件判断,以达到匹配的效果,从而降低圈复杂度。在写这道题时,也踩了几个坑,在编写条件判断式时逻辑混乱,将等腰直角三角形的判断语句放在等腰三角形和直角三角形之后,导致一直无法输出正确的结果,还有就是浮点数的比较不能直接使用==进行判断,因为浮点数在计算机中采用的储存方式是近似的,如果直接比较的话可能会因为误差原因导致结果不正确。这里应该要采用做差小于一个数的方式来进行浮点数的比较。总体而言,题目集一的7-8难度不高,但是要求有很高的逻辑性,代码也需要继续优化。
题目集二的7-4和7-5,都跟日期打交道,7-4是求给定时间的下一天,而7-5则是进阶版:求前n天,n可正可负。下图是对7-4的圈复杂度分析

可见最大复杂度为7,平均复杂度为5.5,代码质量较高

在这个程序中用到的四个方法中,checkInputValidity()和nextDate()的圈复杂度较高,均为七,分析两个方法的代码
public static boolean checkInputValidity(int year,int month,int day) {
int[] x = new int[] {0,31,28,31,30,31,30,31,31,30,31,30,31};
if(year<1820||year>2020||month<1||month>12||day>31||day<1) {
return false;
}
else {
if(isLeapYear(year))
x[2]++;
if(x[month]<day)
return false;
else
return true;
}
}
checkInputValidity()方法中调用了isLeapYear(),并且该方法有三个出口(即三个return),这是圈复杂度增加的主要部位,改进方法:可以将两个return false;整合到一起不采用if语句的嵌套,这样预计圈复杂度能降到4左右。
public static void nextDate(int year,int month,int day) {
int[] x = new int[] {0,31,28,31,30,31,30,31,31,30,31,30,31};
if(isLeapYear(year)) {
x[2]++;
}
if(month==12&&day==31) {
year++;
month=1;
day=1;
}
else {
if(x[month]==day) {
month++;
day=1;
}
else {
day++;
}
}
System.out.print("Next date is:"+year + "-" + month + "-" + day );
}
nextDate()方法是判断下一天的方法,在编写方法的时候就已经在考虑算法复杂度的问题,如果采用大量的if语句对某个月进行计算时,势必导致大量的逻辑判断,从而增加算法的复杂度,所以我在这个程序采用的是预设一个静态数组,数组中以下标为月,数组中存放的为每个月的天数。这样的话对月份天数的读取就十分方便,既没有if语句的高复杂度,也没有switch语句的臃肿。可以说是很简洁,很漂亮。我对这段代码是没有要改进的地方,复杂度也在可接受范围之内。总体来说,7-4的难度也不高,耗时也不长,在提交代码时主要遇见的问题就是nextDate()方法出现的逻辑问题,但这也是由于在编码中的逻辑紊乱而出现的小毛病。
接下来对7-5进行代码分析,还是先贴上使用SourceMonitor对7-5进行的算法复杂度的分析图

最大复杂度为11,超过了10,应该还有优化空间,然后分析具体方法的复杂度

daygo()方法的复杂度为整个程序中最高的,而checkInputValidity()基本是搬运自7-4中的方法,圈复杂度为6,比7-4中的7小,下面将具体分析daygo()方法:
public static void dayago(int year,int month,int day,int n) {
int[] x = new int[] {0,31,28,31,30,31,30,31,31,30,31,30,31};
int flag=0;
if(isLeapYear(year)) {
x[2]++;
}
if(n>0){
if(day>n){
day-=n;
}
else{
month--;
if(month<1) {
month=12;
year--;
}
day=x[month]-(n-day);
}
}//n天前
else{
n=-n;
flag=1;
if(x[month]<(day+n)){
month++;
if(month==13) {
year++;
month=1;
day=(n+day)-x[1];
}
else
day=(n+day)-x[month-1];
}
else{
day+=n;
}
}
if(flag==1)
n=-n;
System.out.print(n+" days ago is:"+year + "-" + month + "-" + day);
}
daygo()方法的算法也是借鉴于7-4中的方法,而主要的使复杂度升高的部分应该是if语句嵌套的部分,而我思来想去也找不到在这部分能改进的地方,然后我发现只要将
if(flag==1)
n=-n;
删去,就可以复杂度降至 10,所以我将这个语句删掉,在else内完成符号的转换,将代码的圈复杂度降至10,如下图。


总的来说,题目集二的7-4和7-5难度都不算高,没有涉及到类间关系,就只有一个Main类,Main下有三个方法,整体设计难度不高,只要清楚了逻辑关系,编写代码就是一件很简单的事了,但是优化代码却有一定难度。
题目集三的两题7-2与7-3,7-2难度不大,主要是类设计的问题,但是7-3求导数题目涉及到字符串的处理,需要用到java中的正则表达式,而后又是类与类间的关系设计,难度较大。下面将对这两个题目逐个进行分析。
题目集三7-2,先用SourceMonitor进行算法复杂度分析,下图为圈复杂度分析图


7-2考察了类间关系设计,定义了一个Main类和Date类,Main类调用Date类,由上图也可以看到,圈复杂度主要来自于Date类,因为此次作业跟题目集二的题目高度相似,所以只要将代码CTRL c加CTRL v,再改一改,实现类设计就好了,类图题目已经给了。
7-3是求导数的题目,需要自学正则表达式来判断输入合法性
Pattern p = Pattern.compile("([+-]?0\\*x\\^[0-9]*)|([+-]?[0-9]*\\*x\\^0)|(^0\\*x)|([0-9]{1,}[ ]{1,}[0-9]{1,})|([+-^]{1,}[ ]*0\\d{1,})|(^[ ]*$)");
Matcher m = p.matcher(str);
if(m.find()) {
System.out.println("Wrong Format");
}
本来是打算做好合法性测试的点的,然后再来求导,结果

合法综合测试这两一直过不去,所以想到了这两个应该是合法的强测,然后老师上课时提到了设计幂函数类所以
public class Fun {
private String strxs="1";
private String strzs="1";
public String getStrxs() {
return strxs;
}
public void setStrxs(String strxs) {
this.strxs = strxs;
}
public String getStrzs() {
return strzs;
}
public void setStrzs(String strzs) {
this.strzs = strzs;
}
public Fun() {
super();
// TODO Auto-generated constructor stub
}
public BigInteger newxs() {
BigInteger xs = new BigInteger(strxs);
BigInteger zs = new BigInteger(strzs);
BigInteger one = new BigInteger("1");
return xs.multiply(zs.subtract(one));
}
public BigInteger newzs() {
BigInteger xs = new BigInteger(strxs);
BigInteger zs = new BigInteger(strzs);
BigInteger one = new BigInteger("1");
return zs.subtract(one);
}
}
设计了一个幂函数类,数据的计算采用BigInteger类型,然后在写主类时,一直卡在取指数与系数那里,并且正负号还不晓得怎么取出来,解决方法暂时还没想到。这次题目集7-3的难度比我预估的要难,以及还没有很快的适应从面向过程程序设计到面向对象程序设计中,类设计的能力还是不足,希望在题目集四中能更深刻的理解类设计。
总结
前三次题目集每次难度和深度都是跨越式的,使我们快速从面向过程程序设计过渡到面向对象程序设计,从基础语法到逻辑关系到类间设计,与课堂内容相结合,从c语言的学习转向了Java的学习。题目集一以八道简单的基础语法题让我快速的适应Java的编程风格,题目集二涉及到的方法的使用与设计,为之后类设计打下了基础,题目集三的类设计开始有了难度,类与类之间的关系,正则表达式的使用成了难点,也让我意识到书上学的东西毕竟还是太少了,软件行业技术更新快,只有不断地去了解学习新技术新方法,才能跟上时代发展的步伐,比如这次作业要用到的正则表达式,超大数据计算BigInteger类型,都是课外学习的内容,我对oop课程没有建议,因为我觉得这样挺适合我的,老师课上讲的都很深刻,拓展一些课外的知识,以及一些软件设计的方法,工具,我觉得这样很适合我们的发展。

浙公网安备 33010602011771号