面向对象程序设计题目集一至三技术总结

面向对象程序设计的前三周的题目集整体难度不高,题目集一主要考察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课程没有建议,因为我觉得这样挺适合我的,老师课上讲的都很深刻,拓展一些课外的知识,以及一些软件设计的方法,工具,我觉得这样很适合我们的发展。

posted @ 2021-04-04 20:51  拔键能留住落樱吗  阅读(101)  评论(0)    收藏  举报