OOP课程第二阶段总结Blog

OOP课程第二阶段总结Blog

 20201328-严振轩

 前言:学习OOP课程的第二阶段已经结束了,较第一次阶段学习难度加大,学习的内容更多,但收获也更多,在此进行对于知识点,题量,难度的分析与个人看法。

(1)题目集4作为第二阶段的开篇,题量虽少难度是这三次作业最高的,其中水文数据的校验与处理是这个阶段难度的上限。其中知识点覆盖到正则表达式的运用,以及实体类,业务类的运用,其他的两个题目,其中日期类题目则是对上阶段该类题型的拔高,运用聚合的思想,将代码效率最大化,图像继承则是对于父类子类的简单入门运用。

(2)题目集5题量上升,题目难度略微下降,同学们入手的门槛降低,前三道题目是对基本知识的复习考查,第四题则是对正则表达式的再次升级运用,其中还需要进行map,set等接口的运用,需要自学完成,第五道题则是基于题目集4的聚合方式的改变,以下会讨论两次不同聚合的不同效果。

 

(3)题目集6题量依旧上升,难度平持与上一次,前四道题是对正则以及排序方式的复习,将基本的正则表达式的运用基础打牢,后续第五道题则是对题目集4图像继承的升级运用,以多态为思想基础进行编程。第六题则是对接口的使用进行了入门引导,需要进行接口方面的自我学习。

 

 

 

 

  各题目  设计与分析  采坑心得  改进建议 :

(1)题目集4:7-2   日期问题面向对象设计(聚合一)

设计与分析

 

 

 

 

       该题目为前几次日期类题目的升级迭代,前几次无非运用简单的方法与类的构建处理即可,这一次则是要运用聚合的思想。聚合的概念为:如果一个类有一个类的实体引用(类中的类),则它称为聚合。 聚合表示HAS-A关系。由前几次的日期类题目操作而言,题目功能方法是需要重复调用的,而聚合也恰好符合的更好的对代码的复用。该题目通过构建DateUtil类对处理结果进行集成处理,再由此衍生出Year类,Month类,Day类,进行不同的处理,共同处理包括验证合法性,以及对于日期增减的操作。该题目复杂度较第一阶段这类题型大大降低,体验出了代码复用性的高效率。其中该题目给出了设计类图,基本框架建立后,只需要明白聚合关系的代码编写语法,则可以流畅的完成题目。其中当其他类完成构建后,主类的书写则非常顺畅,开始体现出面向对象编程的一点影子,需要我们去灵活运用。

采坑心得

 

public boolean compareDates(DateUtil date){//验证输入的两个日期是否相同
		        if (date.getDay().getMonth().getYear().getValue()<this.getDay().getMonth().getYear().getValue())
		            return false;
		        
		        else if (date.getDay().getMonth().getYear().getValue()==this.getDay().getMonth().getYear().getValue()
		                &&date.getDay().getMonth().getValue()<this.getDay().getMonth().getValue()) 
		            return false;
		        
		        if (date.getDay().getMonth().getYear().getValue()==this.getDay().getMonth().getYear().getValue()
		                &&date.getDay().getMonth().getValue()==this.getDay().getMonth().getValue()
		                &&date.getDay().getValue()<this.getDay().getValue()) 
		            return false;
		        
		        return true;
		    }

 

        以该题目中,验证两日期是否相同的主类调用方法为例子,其中对于年月日的调用,若代码语法不符合以上代码的例子,则会出现报错,或者无法真正完成年月日的正确处理与正确校验。其中,再编写该题目之初,未熟悉聚合的语法规则,导致对于年月日的处理方法与校验方法,都未采用类似date.getDay().getMonth().getYear().getValue()这样的写法,写法都只是用直接的year,month,day进行处理,导致代码运行后,得不到结果而且会出现报错。后及时了解写法后,发现需要这样进行处理,则进行的及时订正。采用后在计算算法正确的前提下,可以得到题目所需的正确结果。

改进建议

  由SourceMonitor以及PowerDesigner软件测评结果可以看到,在圈复杂度上,较上个阶段的日期类题目已经大幅下降,这时需要考虑的是对于不同数据的处理上,如何做到有效处理,如何处理有序不混乱。该题目所给的类图而言。其中年月日进行的是连续性处理,年月日存在关联性,既通过先处理日,再处理到月,再处理到年。虽然代码在聚合的条件下更为严谨,但若中间出现错误,则直接无法得到正确结果。例如中间出现算法错误,则会导致得到结果不符,不知从哪个方面修改。其中编写代码就出现过,代码语法没问题,却就是得不到正确结果,反复测试才知道,月校验上出现问题。既需要改进的方向,是对于年,月,日有着集成的处理方式,在对代码的复用性下,分门别类的处理较连贯性处理更具可视性与可维护性。

 

(2)题目集5:7-4   日期问题面向对象设计(聚合二)

设计与分析

 

 

 

 

        该题目较题目集4的日期类题目,虽都同为聚合类型,但聚合的方式不同,该题目的聚合方式类似我对上题分析的改进的模式。其中大体聚合方式便是分开独立处理年,月,日,最后集成于DateUtil完成是输出结果的集成效果。本题目设计的框架:通过将所需的不同功能的分门别类,在主函数通过switch语句引导,进行不同功能的对象的创建。不同的功能统筹在DateUtil类中进行详细划分:闰年判定,前N天,后N天,相差天数等,其中DateUtil类仍是一种大体功能类,大多数详细的小步处理,是通过Year类,Month类,Day类进行详细处理。其中不同于题目集4的日期类题目,这次的聚合不再是连锁性聚合,而是年月日聚合于DateUtil上,互不关联,最终在DateUtil上完成统筹处理,相当于DateUtil为中心工厂,按需向Year,Month,Day中调用所需要的方法。设计有所缺陷在于,没有完全去调用到小类中的方法,更多的处理依旧堆积在DateUtil中。在复杂度平持于题目集4,实际代码书写却更加简洁可观,是一次升级的聚合。

 

 

 采坑心得

public DateUtil getNextNDays(long n) {
              int year = this.year.value;
                int month = this.month.value;
                int day = this.day.value;
                int[] arrx = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};//月份的最大天数
                for (int i = 0; i < n; i++) {
                    day = day + 1;
                     if (month == 2 && isLeapYear(year) && day > arrx[month-1]+1) {
                            day = 1;
                            month = month + 1;
                            if (month > 12) {
                                month = 1;
                                year++;
                            }
                        }//如果月数天数拉满,则跳转到下一个月,如果月数拉满到12月,则跳转到下一年
                     if (month == 2 && !isLeapYear(year) && day > arrx[month-1]) {
                            day = 1;
                            month = month + 1;
                            if (month > 12) {
                                month = 1;
                                year++;
                            }
                     }//此处考虑闰年的情况,如果是闰年,则在二月的最大天数上+1
                     if (month != 2 && day > arrx[month-1]) {
                            day = 1;
                            month = month + 1;
                            if (month > 12) {
                                month = 1;
                                year++;
                            }
                        }//此处考虑了闰年2月以及天数是否越界     
                      
          }

        以求下N天的方法为例子,其中题目集4求下N天,我采用的确定下一月的的最大天数,是通过调用该方法之外的另一个确定最大天数的方法,以确定到对应月份的最大天数。在上一道题目并不存在最大整型数测试。所以可以通过全部的测试点。这一次的日期类题目出现的最大整型数测试,如此方法间的反复调用,导致出现运行超时以及得不到正确结果的问题。所以在题目集5中,我将确定最大天数的方法取消,改之放置在功能方法之中作为一个过程,这样解决了得不到正确结果的问题,代码运行时间也大大缩短。另外更改的方面还有在求下N天的天数n类型的转变,本来n的类型为int型,在后续完成了算法确认无误,测试点只剩下最大整型测试无法通过,这时无论如何更改都无法通过,原因是“运行超时”,其中修改过算法,进行过测试,在pta上就是运行超时,后尝试去改变了n的类型后,由int型转为Long型,这时在PTA上就完美通过了。

改进建议

   该题目较题目集4的日期类题型,是做到了聚合的优化,无论是代码可视性还是代码的简洁性都有了极大的提高。而需要改进的地方是对于方法的使用。其中在DateUtil类中,个人加了几个方法进去,而且在Year,Month,Day类中的+1,-1功能没有进行过调用。需要改进的地方在于可以尝试将类似于求下N天,求上N天,求两日期的天数差的方法中,尽量不夹杂着多余的算法步骤,能从已有的类方法中调用,就从方法调用。这样不仅仅可以提高代码可读性,在代码复用性上也有极大的提高。以及在面对超过最大整型数的测试上,若有此需求,可以尝试用大数完成题目的数据测试升级。

 

优劣比较  题目集4:7-2 日期问题面向对象设计(聚合一)&& 题目集5:7-4 日期问题面向对象设计(聚合二)

聚合一:作为第一次聚合,聚合点在于DateUtil与后续的Year,Month,Day类的连结。并不算是完全的聚合形式。其中对于数据的处理更为严谨,若算法问题不存在问题,则得到的结果基本上不存在差错。反之代码可读性大大降低,以及代码操作不方便,代码亢长。

聚合二:作为第二次聚合,聚合中心是DateUtil类,该类连结着Year类,Month类,Day类,其中数据处理类似于年月日独立处理,初始结果集成在DateUtil类中,最终得到最后的输出结果,代码操作更为直接可观。

以下从代码运行时间,代码可观性,以及复用性上进行优劣比较:

运行时间

聚合一

 

 

 聚合二

 

 

     在代码运行时间上:并没有很大的区别,其中运行时长的是聚合二中的最大整型测试,其中聚合二中处理数据更为合理,虽然略微超出聚合一的运行时长。

 在代码可观,可读,操作性上:聚合一的代码亢长,为了调用到指定的属性,例如年,还需要分别调用到日,月,再能调用到年。在DateUtil类方法中代码亢长,过于累赘,操作性上不方便,甚至不利于后期修改。

相对而言聚合二就需要调用什么属性就调用什么属性,不需要走一个固定相同的路线,即调用属性不需要被其他属性限制。作为代码的书写者自然更偏向于聚合二的写法,相对而言作为代码阅读者的话,也更想看到代码二的写法。以下呈现不同聚合方式在相同方法下的代码写法,直观比较二者。

聚合一:

 

聚合二:

 

  在代码复用性上:聚合一虽然降低了代码的复用性,但在类中多次调用方法需要走多少次相同的路的路向。而在聚合二中,DateUtil依旧是一个做统筹计算与合法的方法。其中聚合二中DateUtil类似于一个中心,当

处理数据的方法需要一个特定的方法验证,则可以自己从Year,Month,Day中进行调用。因为聚合二中Year,Month,Day是与DateUtil直接相关,则调用起来非常的方便,直接了当。复用性而言,本题类似于天数的+1,-1是一个需要循环调用的方法,采用聚合二的聚合方式,则可以大大提高代码的复用性,便是不必要多余的代码,用统筹的代码做更多的事。合成/聚合复用原则是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新的对象通过向这些对象的委派达到复用已有功能的目的。效率方面由分析运行时长可知,运行下无太大的差别,其中,在代码复用下,与聚合的样式,聚合二更是个优秀的聚合方式。

 

(3)题目集4:7-3   图形继承

设计与分析

 

 

     该图像继承题目主要的设计思路是父类,子类的构建,通过在父类中写出主要的功能方法代码,再在各个子类中复写出同名的方法,给予不同的计算形式。通过主类中new出不同的对象,该对象找到对应的类方法,完成所需输出的计算。其中关联到主类中输入的数据如何调用到构造方法,通过调用构造方法,进而调用得到类似求面积,求体积的方法。其中需要自学:父类子类的构建,String.format保留小数的方法,重写方法,以及父类子类对应到主类的构造方法调用。该题目所需的工作量并不大,主要在熟悉继承的规则后,只用完成功能方法的编写,就可以快速的完成主类方法的补充,进而完成题目。

采坑心得

 

 

      以选择矩形形式为例,在起始阶段,未了解到继承调用构造方法的语法,并没有rectangle.setLength(lengthx);以及rectangle.setWidth(widthx);这两步,导致程序报错无法运行。后续查阅了论坛,了解到继承的规则以及基本的输入,调用语法,才得以将1输入的内容传入方法中,得以正确调用求面积方法得到答案,其中仍需要注意在求面积方法上,只用调用,不需要再说明传入的内容。

改进建议

  该题目功能子类受制于父类。若需要更多的功能子类可以有一个统一的调用中心,则用父类继承,会导致代码空间受制于父类。因此可以学习到接口,接口在符合规则的前提下,其他的功能子类都可调用到接口中同名的功能方法,接口中的抽象方法都得以实现,且多个无关的类可以实现同一个接口,一个类可以实现多个无关的接口。因为接口的属性和抽象方法默认是必须公开的(public)所以如果有需要保护private(私有)的属性或者方法时,必须用继承一个类(抽象类也是类)。

 

(4)题目集6:7-5  图形继承与多态

设计与分析

 

 

 

 

    从键盘首先输入三个整型值(例如a b c),分别代表想要创建的Circle、Rectangle及Triangle对象的数量,然后根据图形数量继续输入各对象的属性值(均为实型数)。其中要求创建的各个图形对象均存储在ArrayList<Shape>类型的列表中,根据图形的面积大小进行升序排序,要求必须对list中的图形对象在list中进行排序,而不是对求得的面积进行排序,排序后再次求出各图形的面积并输出。其中通过构建父类Shape存入抽象的求面积,以及校验合法性的抽象方法。与题目集4图像继承不同,其体现出了多态性,多态即对象在不同情况下的不同表现,具体体现在定义和功能两个方面,简单的总结一下,多态可以用“三个定义和两个方法”来总结。三个定义分别是父类定义子类构建、接口定义实现类构建和抽象类定义实体类构建,而两个方法分别是方法重载和方法重写。其中对于对象的存放,采用了Linklist存放对象,后续通过列表中对象对应的图形不同,通过抽象方法,指引到指定类的实体功能方法,得到所求的面积。后续根据插入排序可以达到排序后再输出的效果,其余的便是再主类中做好输出内容的预设,以及对象的创建,最后再通过以上的描述,得到正确结果。

采坑心得

 

 

 

     首先在对所有对象求面积处理之后,便通过插入排序得到排序后的结果。其中编写习惯是排序中对数值进行比较,比较直接交换数组中数值的位置,以此完成插入排序。而在Linklist中,数值对比需要对象求出面积后进行对比,而列表中完成排序的交换,则是通过对象的位置交换。其中直接赋值型的交换是会报错的。后在书上找到了List.set方法,用于完成列表中元素的交换位置。所以列表中的位置交换不同于数组,需要注意交换元素的类型。

     该部分为判断圆的合法性,原本内容意思为,若半径小于0则不合法,但第一次上交后没有满分,还要圆合法测试无法通过。后将半径的合法调整为小于等于0,就完美通过了,既做题需要熟悉对应题目的指导书以及解题报告再进行对比自己的idea,后再开始写代码,修改任务虽小,但是希望后续代码能够严谨确定要求后再进行编写。

改进建议

     题目中的输出结果中,需要在主函数中打印出对应的内容,改进方面可以尝试创建一个专门用来打印字样的类,这样可以让主函数更为简洁。以及对于list接口的使用,可以更为灵活,尝试将排序以及面积对象存放设计的更为直观。

 

(5)题目集6:7-6  实现图形接口及多态性

 

 

 

 

      本题通过设计一个程序,通过继承性,封装性以及多态性完成输入对应属性求面积的功能。其中封装性体现在Circle类以及Rectangle类中私有属性的创建。java中多态性的意思是作为面向对象的程序设计语言最核心的特征,表示一个对象有着多重特征,可以在特定的情况下表现出不同的状态,从而对应着不同的属性和方法。多态是同一个行为具有多个不同表现形式或形态的能力。而本题便是以求面积为公共事物,不同的图形形状为不同的形式。通过定义了一个接口,使得所有符合接口接入特性的类都可调用到接口中的抽象方法---求面积,进而调用出实体方法。java中的接口类似于生活中的接口,就是一些方法特征的集合,但没有方法的实现。在不同子类中,完成实现方法的代码内容。

 采坑心得

 

 

     初学接口的运用,导致习惯性继承上使用父类子类继承的extends,而接口子类接入方法应该用imolements,通过查看菜鸟教程才得知接口语法有错。

 

     以上也是语法方面的问题,定义对象时并未如上图一般定义,而是如下写法:

 

     这样会导致代码无法得到结果,原因是定义需要通过接口,再接入到子类中,完成对象的创建。

 

 改进建议

 

 

 

 

正则表达式技术的分析总结

 

水文数据校验及处理

 

".*[|].*[|].*[|].*[|].*"//用于校验输入数据格式的合法性
"([1-9]([0-9]{1,3})/(([13578]/(([4-9])|([1-2])([0-9]?)|[3][0-1]?))|([2]/(([3-9])|([1-2])([0-9]?)|([1-2])([0-8]?)))|([469]/(([4-9])|([1-2])([0-9]?)|[3][0]?))|([1][0]/(([4-9])|([1-2])([0-9]?)|[3][0-1]?))|([1][2]/(([4-9])|([1-2])([0-9]?)|[3][0-1]?))|([1][1]/((([4-9])|[1-2])([0-9]?)|[3][0]?)))) (([1]{1}[02468])|(2[024])|([0]|[2]|[4]|[6]|[8])):00"
//用于检测输入数据的内容合法性

 

  本次题目所用的基本正则表达式如上,第一主要用于实现输入格式合法性的检验,既四个|作为分割符号是关键,也是基本的入门判断。第二步则是根据指导书所要求的数据范围,做到对格式符合的数据,进行数据内容合法性的校验。其中有数值范围要求,数据保留小数位数要求,时间格式要求,都需要细致的正则表达式要求。正则表达式采用分段检验,既从左到右一一检验,完成一连串字符串的检验。

 

统计Java程序中关键词的出现次数

".*//.*"  //用于检测数据的//以及后续字符
str1 = strx[i].replaceAll("//.*", " "); //用于将上述检测到的字符串替换为空格
".*/\\*.*?\\*/.*" //用于检测/* 与*/之间的字符
str2 = str1.replaceAll("/\\*.*?\\*/", " ");//将上述检测到的字符替换为空格
".*\\\"([^\\\"]*)\\\".*"//用于检测[]
str3 = stry.replaceAll("\\\"([^\\\"]*)\\\"", " ");//将上述检测结果替换为空格
str4 = strz.replaceAll("\\p{Punct}", " ");//将检测到的标点符号替换为空格

  以上正则表达式的运用到检测指定字符之后,指定字符之间,指定字符的语法规则。其中通过检测到后替换为空格,剩下有效信息后,进行关键字检索。

 

正则表达式训练-QQ号校验

"^[1-9][0-9]{4,14}$"//用于检测QQ号

满足以下要求: 5-15 位;0 不能开头;必须都是数字。 基本为简单的字符串正则表达式处理,处理位数,字符开头检测以及字符形式检测。

 

正则表达式训练-验证码校验

("[0-9a-zA-Z]{4,}"//用于检测验证码

满足以下条件:由四位数字或者字母(包含大小写)组成的字符串。 该正则表达式用于检测字符串类型以及字符串长度。

 

正则表达式训练-学号校验

("2020((1[1-7]|61|7[1-3]|8[1-2])(0[1-9]|[12]\\d|3[0-9]|40))")//用于检测学号

  满足以下条件:1、2位:入学年份后两位,例如20年;3、4位:学院代码,软件学院代码为20;5位:方向代码,例如1为软件工程,7为物联网;6位:班级序号;7、8位:学号(序号)。

运用的正则表达式用于分段式字符串检测,字符串中有固定的字符,只需要简单的通过正则表达式描绘出特性即可以完成检测。

 

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

 

 

 

 

 

 

 

".*//.*"  //用于检测数据的//以及后续字符
str1 = strx[i].replaceAll("//.*", " "); //用于将上述检测到的字符串替换为空格
".*/\\*.*?\\*/.*" //用于检测/* 与*/之间的字符
str2 = str1.replaceAll("/\\*.*?\\*/", " ");//将上述检测到的字符替换为空格
".*\\\"([^\\\"]*)\\\".*"//用于检测[]
str3 = stry.replaceAll("\\\"([^\\\"]*)\\\"", " ");//将上述检测结果替换为空格
str4 = strz.replaceAll("\\p{Punct}", " ");//将检测到的标点符号替换为空格

该题目首先通过正则表达式对干扰的符号进行清除替换,以上正则表达式的运用到检测指定字符之后,指定字符之间,指定字符的语法规则。其中通过检测到后替换为空格,剩下有效信息后,进行关键字检索。

运用字符串处理后的字符内容仅仅存在可被识别的一个个英文单词,此刻运用hashmap进行检索匹配。

HashMap:它根据键的hashCode值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。 HashMap最多只允许一条记录的键为null,允许多条记录的值为null。

将java关键字都储存于数组,将数组放于hashmap中,通过对hashmap遍历的运用,可以对剩余的有效内容进行检索,完成标记与最终输出。

 改进建议

  通过powerdesginer软件可以看出本次程序都描述在主类中,并没有构建出其他的类,改进方面可以在通过构建消除干扰符号类以及检测类两个大类,主类直接为输入字符串new一个对象,只用调用创建类中的功能方法,可以使代码在主类中更为简洁,各类各尽其职,分工明确,代码复用性更高,可读性更强。

 

 

第二阶段Blog总结

  第二阶段通过三次题目集也落下帷幕,第一次阶段总结的最高潮是类设计,而本次的三次题目集基本所有的题目都以类设计为基础,完成题目的构建。在类设计的基础上,通过对继承,多态,接口等多方面学习,认识到类设计不是单一的去设计一个方法完成功能。面向对象编程的思想,也在本次学习真正拉开了序幕。面向对象编程不同于面向过程编程,在创立一个对象后便有明确的功能性,通过继承,多态,接口可以实现不同对象实现不同的功能。其中在类设计上,通过学习类属性的访问权限,初步了解了四种访问权限:public,private,protected,default;以及不同类的类型:实体类,业务类,接口类;对于类设计上,学习的多,代表思路与编程思想变得更为开阔且严谨,开始真正考虑到如何将一个题目设计到恰如其分,其中日期的聚合题目让我深入的感受到,不同的设计思路带来的不同效果。

  对于技能上的学习,在对字符串的校验处理上,通过对正则表达式的深入学习,掌握对复杂数据的校验,截取,替换等,作为一项工具使用,在程序复杂度上大大降低。以及对于list的学习,可以对多对象处理上更为便捷可观,多对象处理上更为有效。还有对于hashmap的学习,对于其中遍历的运用进行了学习,对于多字符校验上有了更广阔的思路。不仅于此,题目集中许多边边角角运用的技能,也是会通过学习得以利用。

  对于课程的学习建议,个人认为目前的pta便是不错的,有难有易,好上手,若想拿满分则必须要去自我学习。自我学习上,课程自带的SPOC课程则是选择之一,我们仍可自己去选择去论坛学习或者其他网课上学习。在实验上,目前进行的农夫过河的迭代性编程,面对同一个问题随着技术加深,我们需要运用更为上层的知识解决同一个问题,这是有趣也充满挑战的。线下课程中,希望老师不仅可以有对知识的讲解,与编程思想的演练,更可以对pta或者实验的难题加以点评与讲解,让作业不会得过且过,而是让我们更为深刻的了解一道题目应该如何去设计。作为学生自身,已经了解到这是一门需要自我探究,自我学习的课程。时间,精力,投入,缺一不可,不去假大空,而是去真正的做。

  第二阶段于此就告一段落了,首先感谢OOP课程的老师与助教的付出,再而感谢还在学习的自己。希望有更好的心态迎接第三阶段!

 

 

 

 

 

 

 

posted @ 2021-04-27 00:21  Yan7zx  阅读(185)  评论(1)    收藏  举报