面向对象第二次博客作业

 

前言:

这个学期的课程已经过半,面向对象的学习内容也越来越深入,从最开始的只要写不到50行的代码到现在需要写一俩百行的代码,我能真真切切的感受到自己学会了很多东西。Java作为现代编程的主流语言之一,其身上有许多独特的魅力值得我们去探索。而pta这个平台就给我们提供了非常好的训练平台,而老师也在pta上布置了一些非常经典的提目,难度也较上三次作业有比较大的提升。

关于三次作业

这三次作业的难度较上三次有比较大的提高,而且题目量也有较大提高。主要是提高我们对多态,接口,继承的使用。老师也稍微降低了提高难度的速度,让我们有更多时间去学习和准备这门课程。这三次题目集最经典的就是日期问题面向对象设计(聚合一)和日期问题面向对象设计(聚合二)这两道题目看似一样,实则大有区别。这三次题目集还是有很多关于正则表达式的题目。正则表达式在平时的代码编写的过程中还是有非常重要的地位的学好正则表达式对我们在之后的代码编写中还是有非常大的好处的。在这三次的题目集中我们开始慢慢接触到了java的核心部分了,多态作为java最核心的部分,能有效的保证代码的可重复利用性,以及方便维护。所以学好多态是学好java的必要条件。

三次作业的主要知识点

  第四次题目集主要知识点是:正则表达式的应用以及类之间的调用,还有继承。主要就是类之间的调用。

  第五次题目集主要知识点是:对字符串的处理,以及一些简单字符串函数的应用,以及对数组的处理,数组函数的简单应用。还有学习了三种整数的排序方法,以及正则表达式的应 用,以及在题目集四的基础 上加深了类之间的调用的关系,让类之间的调用更方便。

  第六次题目集主要知识点是: 对字符串的简单应用,以及正则表达式的简单应用。第六次题目集也涉及到了java的核心部分:多态。还有接口。

设计与分析

1. 日期问题面向对象设计(聚合一),这道题目的主要目的还是要我们熟悉类之间的调用。这道题总共有四个类:日,月,年,以及一个关于日期计算的类,我们要在三个日期类中完成类之间的调用以及完成本类中的日期计算。在类中的数据的封装性也要完成,因此需要生成get以及set方法。在不同他类中用不属于本类的数据以及方法是一点要先声明,当时我在写这道题目的时候就是因为不声明导致一直报错。直到看了书才知道问题所在。还有就是关于计算俩个日期之间的天数的。我一开始并没有什么思路,主要是闰年的存在让天数的计算变得更加困难。最后还是采取了将一年中的所有天数放在一个数组中然后在判断是不是闰年,是闰年天数就加一。代码如下

 private static final int[] mon = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
  days = 365 * (dateUtil2.getYear() - dateUtil1.getYear()) + leapYearNum;

        int d1 = mon[dateUtil1.getMonth() - 1] + dateUtil1.getDay() + (dateUtil1.getMonth() > 2 && isLeapYear(dateUtil1.getYear()) ? 1 : 0);
        int d2 = mon[dateUtil2.getMonth() - 1] + dateUtil2.getDay() + (dateUtil2.getMonth() > 2 && isLeapYear(dateUtil2.getYear()) ? 1 : 0);
        return days - d1 + d2;

根据类图还有圈复杂度可以看出这道题目做的不是很好。最高的圈复杂度达到了6。在算法方面还有待改进。根据类图可知,这道题目的四个类是相互调用的,因此调用的次数比较多。从类图中可以看出,在改变自己本类的数据时都是在自己本类进行操作,比如Day类中的resetMin及dayIncrement  方法。都是对自己本类的数据进行操作,这体现了类的封装性。

2 .日期问题面向对象设计(聚合一),这道题目看似和聚合一一样实则其实有很大不同,其中的对类的调用方法是完全不同的,虽然说也是四个类,但是调用起来会比聚合一要更简单一些,在代码方面我也做出了一些改进,在计算俩个日期相距的天数时我直接根据前俩个方法,判断日期先后以及判断日期是否相等,然后在根据计算前N天的方法计算。代码如下:

        public int getDaysofDates(DateUtil date)
        {
            DateUtil dateUtil1 = this; 
            DateUtil dateUtil2 = date; 
            if (dateUtil1.compareDates(date)) {
                dateUtil1 = date;
                dateUtil2 = this;
            }
            int i = 0;
            while(!dateUtil1.equalTwoDates (dateUtil2)) {
                dateUtil1.getNextNDays(1) ;
                 i++;
                }
            return i ;
            }

 

 

 

 

 可以看出聚合二的平均圈复杂度以及最高的圈复杂度都比聚合二要小,说明经过改写后的代码更加清晰明了,可行性更高。

3. 聚合一和聚合二的优劣

刚写这俩道题目的时候我还以为是俩道一样的题目,因为他们要实现的功能是一模一样的,但是经过我的仔细观察,发现俩道题目的类图完全不一样,聚合一的代码应该要比聚合二的代码质量要差一点,首先,聚合一的平均圈复杂度要比聚合二的更低,其次聚合二的耦合度要比要比聚合一更低,所以聚合二的可维护性要比聚合一更高,以及安全性也要高。因为非常耦合性越高就越像物理里的串联只要其中一个类有问题,那么整个代码就会出现非常大的问题。反之耦合性越低,就说明类与类之间并没有太大的联系,就像物理里的并联,相对独立,其中一个类出现问题对整个程序的运行并没有太大的影响。所以经过这俩次的题目集之后我对类之间的联系又加大了理解。

4. 题目集4(7-3)

这道题目主要就是对于继承的使用,要用继承我们首先创建一个父类,创建父类可以减少代码的复写,子类要是属于父类的一个分支。就比如这道题,父类是图形类,他的子类就是圆,长方形,正方形等等。然后我们就可以在父类中声明我们在子类中需要使用到的方法。比如这道题目中的求面积‘在所以的子类都需要使用,因此我们可以在父类中声明。

重类图以及圈复杂度图中可以看出,代码还是比较简单的,类中并没有太多的方法,功能也比较简单就可以实现。

5.题目集6(7-5)

写这道题目的时候我还是有点把握的,因为有题目集4的7-3的1经历。开始当开始做的时候还是有点不会写,主要是这道题目要用动态数组,而且要在动态数组中进行排序,因此我也恶补了很多关于动态数组的方法,怎么在动态进行排序这是困扰我的最大的一个问题。后来我发现可以用Arrays的Collections方法进行排序。还学会了多态的使用。,多态可以用“三个定义和两个方法”来总结。三个定义分别是父类定义子类构 建、接口定义实现类构建和抽象类定义实体类构建,而两个方法分别是方法重载和方法重写。本次作 业我们采用的是抽象类定义、实体类构建的方式。即 Shape 为抽象类,Circle、Rectangle 及 Triangle

为实体类。

从类图以及圈复杂度图来看,代码的整体思路比较清晰,圈复杂度不高,但是还是可以有改进的地方。

6 .题目集6(7-6)

这道题目整体上貌似和题目集四的7-3没什么区别,只是多了一个接口,抽象类是从多个类中抽象出来的模板,如果将这种抽象进行的更彻底,则可以提炼出一种更加特殊的“抽象类”——接口(Interface)。接口是 Java 中最重要的概念之一,它可以被理解为一种特殊的类,不同的是接口的成员没有执行体,是由全局常量和公共此根据接口的概念,这种情况是可以用接口的,他为我们的抽象方法提供了方法的插入点。

7. 正则表达式

经过这几次题目集的熏陶,我发现了正则表达式这东西是真的好用。1.2.3.用。

Pattern pattern = Pattern.compile("\\b"+gjc[i]+"\\b");//创建关键词的正则表达式
            Matcher matcher = pattern.matcher(b);//字符串与关键词匹配

这个就可以匹配之前创建的数组里的东西。

boolean regex = qq.matches("[1-9][0-9]{4,14}");

这个正则就可以匹配第一位是1-9剩下的4-14位随机的qq号了。

boolean regex = qq.matches("[A-Za-z0-9]{4}");

这个正则可以匹配4位大写字母小写字母以及数字的随机组合。

boolean regex = qq.matches("^2020((1?[1-7])|(7?[1-3])|(8?[1-2]))((0?[1-9])|(1?[0-9])|(2?[0-9])|(3?[0-9])|(4?[0]))");

这个正则可以匹配已2020开头如果第五位是1则第六位需要为1-7或者第五位为7则第六位要为1-3或者第五位为8则第六位要为1-2.

8. 题目集5(7-4)中Java集合框架应用的分析总结

7-4是要统计java中的54给关键字,而且不需要 // 和/*/之后的内容。所以我们需要把这些关键字从文本中提取出来放进一个数组中

for(i=0;i< gjc.length;i++) {
            Pattern pattern = Pattern.compile("\\b"+gjc[i]+"\\b");//创建关键词的正则表达式
            Matcher matcher = pattern.matcher(b);//字符串与关键词匹配
            n=0;
            while(matcher.find()) {//找到该关键词的话,记录该关键词的次数
                n++;
                //System.out.println(matcher.group());

            }

利用一个For循环,寻找在数组中的关键字,找到加一。

还有就是去掉//和/*/之后的东西

kg = x.nextLine();
        while( !kg.equals(exit)) {
            a.append(kg.replaceAll("//.*", " ").replaceAll("\".*\"", " "));//去掉"//"后和的内容以及双引号里的内容
            kg = x.nextLine();
            flag=1;
        }
        String b = a.toString().replaceAll("/\\*\\s*.*\\s*\\*/", " ");//去掉"/* */"里的内容,放入字符串b中

利用repianceAll方法即可。

采坑心得

说实话这几次题目集踩了不少坑。

1.在写聚合一的时候,在那个计算天数的那个主类中,我一直没有声明其他类的存在,导致我一直运行的结果为空,在我认真检查了在其他类是否能够传入数据之后,我才发现数据并没有传入计算类中,于是我

上网查询才知道,在其他类中使用不是本类中的数据及方法时是要进行声明的。

2.在写聚合二的时候,我所有结构都以及搭建好的情况下,无论我是输入加N天还是减少N天,结果总是莫名其妙的多十几天或者少十几天。我认认真真的检查了十几次代码都没有发现问题。最后还是一遍一遍试过才知道总是在二月的时候出问题,于是我看是不是闰年的问题,发现并不是,最后才知道在计算前N天和后N天的时候。一到二月是闰年,不管之后是不是闰年二月都为29天。那时候我的代码是这样的

public int returndays()
    {
               if(year.isLeapYear()==true && month.getValue()==2) {
                mon_maxnum[month.getValue()]=29;
           }
public DateUtil getNextNDays(long m) {
        for (long i = 0; i < m; i++) {  
            day.dayIncrement();
            if (day.getValue() >returndays()) {
                setDayMin();
                month.monthIncrement();     
                if (month.getValue() > 12) {
                    month .resetMin();
                    year.yearIncrement();
                }
            }
        }
       return new DateUtil(year.getValue(),month.getValue(),day.getValue()) ;
    }

后来才知道要改回来。即

if(year.isLeapYear()==true && month.getValue()==2) {
                mon_maxnum[month.getValue()]=29;
           }
               else {
                   mon_maxnum[2]=28;
               }

改进建议

我感觉聚合二的声明其他的类应该要在switch的前面

switch(a) {
    case 1 :
        int ye = input.nextInt();
        int mo = input.nextInt();
        int da = input.nextInt();
        Day day = new Day(da);
        Month month = new Month(mo);
        Year year = new Year(ye);
        DateUtil date = new DateUtil();
     
setDay(day);
        date.setMonth(month);
        date.setYear(year);

如果像这样的话每次都要重新声明非常麻烦。

还有题目集5的 7-2 合并两个有序数组为新的有序数组

可以不用创建一个新数组一个一个排,直接把俩个数组合并在一起,然后在用sort方法。代码如下

int[]d=new int[x+y];
       for( i=0;i<x;i++){
           d[i]=b[i];
       }
      for( i=0;i<y;i++){
          d[x+i]=c[i];
      }
        Arrays.sort(d);

总结

经过这三次题目集的训练,学到了很多,最开心的就是了解到了多态是一个怎么样的东西,多态是打开java这门课程的钥匙,只有学到多态才可能学到java这门课程的精髓。除了多态我还了解到了渐进式图形继承设计的思路与技术运用(封装、继承、多态、接口等)。封装是大部分类都需要用的一个技术,有了封装客户的数据,才能受到安全的保护,而继承则可以很好的为我们减少代码的重复,增加代码的可读性和精简。我认为对于多态方面我还是需要多多加强训练。以及加强逻辑思维的能力,能够实现类的关系设计。

posted @ 2021-05-02 04:19  逐风228  阅读(208)  评论(0)    收藏  举报