OO第四单元总结
目录
(1).第一次作业

本次作业,笔者除Main主类外,新建了四个类。
a.MyGraph。
MyGraph类负责将属于同一个Class或Interface的指令提取出来,整理成一个以相应类或接口的Id为键值的集合(出来对于UMLASSOCIATION以及 UMLASSOCIATIONEND指令,会在END两端对象的指令集合中均添加相应指令),然后进行所有类和接口的实例化,并建立相应的hashMap用于存储实例化的元素。

b.MyClass和MyInterface。
MyClass对应类图中的一个类,其中存储着描述该类所需要的一些属性值。
注意到Interface和Class在逻辑上很相似,因此笔者的MyInterface类直接继承MyClass类,但注意到Class是单继承的,而Interface是多继承的,因此笔者直接把MyClass中存储父类的那个属性值改为了HashSet的形式。其实这里更好的方式是在MyInterface中根据自身的需要对父类中的某个属性进行修改,此处是笔者本次作业的一个缺陷。
c.MyUmlInteraction。
MyUmlInteration是方法的集合,与MyClass、MyInterface、官方包中的函数以及主类进行交互。MyGraph将存有实例化好的HashMap传给MyUmlInteraction,MyUmlInteraction进行方法的实现。
类图如下:

(2).第二次作业
此次由于MyUmlGenerationInteraction涉及方法较多,因此笔者新建了一层中间层:MyUmlClassInteraction、MyCollaborationInteraction、MyStateMachineInteraction、MyCheckForUmlInteraction。
a.MyGraph。
MyGraph和第一次一样,负责整合指令以及实例化相应模型。但是为了使用方便,采用了单例模式。
b.MyCollaboration和MyStateMachine。
由于新增状态图和顺序图而增加,存储一个状态图和顺序图所需要的必要信息。
c.MyUmlClassInteraction、MyCollaborationInteraction、MyStateMachineInteraction、MyCheckForUmlInteraction。
中间层,各类型模型方法的接口,其中有对应方法的相应实现,向下与MyGraph、类、接口、状态图、顺序图等交互,向上与MyGeneralInteraction交互。
d.MyGeneralInteraction。
中间层四个函数中方法的集合,向下与中间层交互,向上与Main交互。

(1)第一单元

整体思路:
ThirdWork是主类,其与三个函数进行交互,Input接受输入,CheckFormal检查是否是合法的表达式,Derivation负责求导。
求导时,先将表达式递归拆解到符合第二次作业表达式的形式,然后利用第二次作业求导的结果得到求导结果,最终得出整个表达式的求导结果。
其中第二次表达式的求导思路是先将项整理为C*X^a*sin(x)^b*cos(x)^c的形式,然后套用该形式表达式求导模板进行求导运算。
并且由于采用的不是递归下降法,因此检查输入表达式合法性时采取用x代换基本表达式因子以及表达式型因子的方式进行处理,看最终是否能得到一个符合第二次表达式的表达式。
(2).第二单元

总体分为三层:输入及主类、调度器、电梯。
InputHandler负责接受输入,然后将输入送至调度器Dispatcher,Dispatcher中事先分配好每条指令应进入的电梯,然后将指令送入对应电梯的等待队列,电梯负责处理自己的指令。Dispatcher相当于一个中间层,虽然名为调度器,但缺少电梯传送给Dispatcher的消息,因此Dispatcher的实际作用相当于一个托盘,并且实现分配好的测略在性能上远远低于采用look算法的测略。
此次作业采用单例模式和工厂模式,单例模式方便了调度器的使用,工厂模式为后期增加电梯提供了方便。但由于没有提取三台电梯之间的共性,因此笔者暴力地直接写了三个电梯的类,使代码显得冗长。
此单元作业的亮点在于是用了调度器这一中间层,将输入和电梯处理解耦,方便了三次作业的扩展,因此,笔者这个单元几乎没有重构。
(3).第三单元

由于最低票价、最低不满意度与最少换乘、最短距离的构图方式不同,因此创建两个图模型:GraphMethod1和GraphhMethod2,总体采用MyPath -> MyGraphMethod -> MyRailwaysSystem的思路构建地铁系统,但由于采用的是复杂度很高的拆点方式,并且有一处查询没有处理好,因此强测出现了tle和空指针异常。但由于修复仅仅是修改了图的构建方法,因此不怎么需要重构就完成了修复。
(4).第四次作业

细致的架构第一部分已经分析,这里不再赘述。总体架构为主类—主交互—交互中间层—四个图。
(5).对OO方法理解的演进。
刚开始接触面向对象的设计思想时,对于老师说的思考“如何写出一份代码不能思考应该先做什么,后做什么,否则就是以面向过程的方法去写代码,而应该从这些要求中提取出一个个类,每个类有自己的职能,各类之间通过信息交流,共同完成一个功能”的想法不太理解,因此在写第一单元的作业的时候,总体还是以面向过程的思想去写的,只是会把一些函数提取到另外一个类中,告诉自己这个类的功能就是什么什么,以为这就是面向对象。
到了第二单元,由于电梯,调度器,接收输入函数每个类的功能通过名字都能很清晰的辨别出来,因此渐渐感觉自己对面向对象的思维有了一点理解,确实是每个类只管做好自己的事,相互之间只以信息进行交流,类与类之间的调用关系都是在一个比较大的层面上的,相比第一单元解耦很多。
第三单元,整体框架由学长提供,我们要做的仅仅是填充几个函数,一个框架要满足所有学生的需求,体现了该架构极高的灵活性以及开闭规则。框架利用了接口,因此能满足所有学生的需求。并且,这一单元我们使用了JML,与以忘用自然语言描述需求不同,JML是严谨的数学语言,用JML描述需求,不会产生歧义。特别是在写了第四单元的作业,深深感觉到JML语言的友善。
第四单元和第三单元一样,整体代码由学长提供,我们负责完善几个需求。自我感觉本单元的架构是我这四个单元以来架构写的最好的。第二次作业抽象出了一个中间层,不管是从代码的美观性,还是从各个部分的闭合性以及交互性来看,我都觉得中间层的作用不可小觑。中间层保证了三类图内部的聚合性,并且在与更高层函数交互时,仅仅通过中间层接口进行交互。每个类各司其职,只管自己的工作。
(1).第一单元
手写数据,黑盒测试。
第一单元主要学习了正则表达式,由于在编写正则表达式时,我是按覆盖的思路去考虑的,因此感觉在判断表达式形式的正确性上,应该不会有大问题,但是我还是和小伙伴一起,按照覆盖的思路编写了测试数据。但是正则表达式是用栈的思想进行匹配的,存在回溯的可能,上网查询了相关资料后,我们采取了侵占模式以避开爆栈的风险。由于是手写数据,因此我们的测试数据仅仅针对正确性,并没有考虑爆栈,只有一两个数据对爆栈进行测试。然而由于笔者手残,有个地方忘加“+”号,并且,由于使用了迭代器,但却没仔细看迭代器的用法,因此还是在互测中流血了。
在前两次的互测中,我通过阅读其他同学的代码找bug,但由于一组有7份代码要看,困于时间与精力,在阅读四五份代码之后就放弃了。
手写数据,黑盒测试不能保证正确性。
(2).第二单元
手写数据->评测机,黑盒测试。
第二单元是电梯,输入数据体现了随机性。电梯单元的第一次作业我和小伙伴还是采用手写数据的方式,粗略验证了代码的正确性,并且输出程序的运行时间,加以验证是否能顺利通过强测。但是手写数据不能保证数据的定时投放,并且随机性不够强,因此本单元的第二次和第三次作业,我通过同学分享的评测机验证自己程序的正确性,并且在互测中验证组员代码的正确性。
(3).第三单元
数据生成器,白盒测试+黑盒测试。
第三单元的主要内容是地铁图+复杂度+JML+JUnit。在本单元以前,笔者写代码很少考虑复杂度问题,但是本单元对CPU时间做了严格的限制,因此不得不关注方法的复杂度。在本单元以前笔者没查看过源码,也没使用过除ArrayList外的数据结构,但是笔者不敢想象没有这两种方法如何完成本单元的任务。在这个单元还是使用了数据生成器生成了一些压力数据对代码进行了测试,但由于第三次作业完成时间较为紧张,因此测试的比较迟,发现复杂度过高的时候,已经没有改进的时间了。本单元还有一个亮点是为我们引入了白盒测试——JUnit测试,可以做到对但个函数进行测试,精确打击bug,提高代码的正确性和鲁棒性。
(4).第四单元
手搓数据,白盒(or黑盒)测试。
第四单元是学习UML画图工具。由于数据生成器已经不再实用,加之CPU时间较为充裕,因此我又和小伙伴们走上了手搓数据的道路,针对每个方法构造相应的图,虽然没有使用JUnit,但笔者认为这算是一种白盒测试。
总体来说,四个单元:
数据构造方法:手写数据 -> 手写数据+数据生成器生成
测试方法:黑盒测试 -> 黑盒测试+白盒测试。
先说说课程感受。
四个单元的OOP学习,过程很漫长,也很短暂,既有JML第三次作业的一脸懵逼以及不想写代码的情绪,也有很想写代码,想做测试,想试试评测机的弱测的惊喜。这个学期,几乎每个周末都有OOP的陪伴,很多时候整个周末都是OOP,有时甚至不到6点就要起床写代码、构造测试数据,然而,有OO陪伴的日子,感觉很充实,感觉自己的编程能力和抗压能力都有了一定的提升。从刚开始接触面向对象时无法理解什么是面向对象的思想,到最后能写出自己认为还算是比较“面向对象”的代码,是通过一日复一日的编程实践总结出来的。
相比往年的体制,我认为今年OO体制改革力度很大,效果也很好,因此在这里很感谢学长以及老师在OO这门课上付出的努力(体制改革+学习内容)。由于第一次作业就在互测中被查出了bug,在知道自己被hack后以及强测结果出来前的这段时间里,是很揪心的,因此不知道自己被查出了多少错。相比往年的互测依靠同组成员自身的道德,今年的体制不仅从外力上限制了恶意刀人的行为,并且提供了bug修复机制,在互测环节为同学们提供了更多的保障。
以下是我对课程收获的一点总结:
(1).代码架构。
架构能体现我们对面向对象思想的理解,能体现我们编程时思路是否清晰。一个好的架构,不仅能符合checkstyle的规则检查,而且能丰富程序的扩展性和可读性。第一单元我从第一次作业到第二次作业经历了一次重构,第三次作业由于实在没有思路,只能采用递归的方式递归到第二次作业能解析的表达式进行处理。第二单元的架构明显比第一单元清晰,由于第一次作业就放置了一个单例模式的调度器,因此增强了程序的扩展性,并且笔者没有采用look测略(这是个遗憾),因此每次作业都能几乎沿用上次作业的代码。第四单元,代码的复用性也很强。
(2)测试。
我们不能保证自己写的代码没有错误,那么测试就是检验代码的最好方式。不论是手写测试数据,还是通过数据生成器生成,不论是白盒测试还是黑盒测试,我们都能通过测试提高代码的正确性和鲁棒性。我觉得对于数据随机性不是很强的测试,手写数据仍然是一个很重要的方式,因为在这个过程中,我们可以加深对需求的理解,也锻炼了思维的严密性。当然,对于边界测试,压力测试,自动化的测试还是很有必要的。
(3)心态。
正如前面所说,一学期的OO学习是艰苦的,但同时也是快乐的。在遭遇挫折时调整好心态,有时反而会给你带来转机。笔者强测出现过一次bug,只有10分,凉的彻底。截至提交当天下午发现代码的复杂度太高,心态有点崩,因此进行逻辑验证时有所懈怠,以至强测6个点出现空指针问题。如果当时能积极调整好心态,说不定能捡回30分。
(4)debug能力。
笔者感觉这学期debug能力有所增强,除了电梯单元单步调试毫无用武之地,其余单元都能通过单步调试去查看代码的执行,验证代码的正确性(或许是idea的debug功能太强大了,哈哈哈)。
(5)JML,UML。
自然语言与数学语言相比,严谨性明显不足,使用JML、UML等描述需求或状态,能减少歧义,方便交流。
(1)每个单元结束公布三次作业标程。一来同学们可以学习标程面向对象的思想,二来同学们可以从三次作业的继承与重构中体会架构设计的思想。
(2)作业发布可否再及时一点。本学期有两三次作业出现了延迟发布的问题,理解学长和老师工作繁忙,但如果有同学做好了从正常发布时间就开始写代码的准备,延迟发布可能会影响他的学习计划
(3)指导书能否再明晰一些,并且尽量减少评测标准的变动。感觉第四单元评测标准变化比较大,对某些同学编写程序造成了一定的影响。这不仅可能涉及到需要修改代码的问题,而且可能涉及无偿评测的次数问题,感觉同学们还是比较在意这两点的。

浙公网安备 33010602011771号