OO第四单元总结博客

@

1. 第四单元两次作业的架构设计

1.1 第一次UML作业

第一次作业的UML架构如下:
在这里插入图片描述
在这里插入图片描述
为了让下一次作业能更好地增加功能,我采用对象组合的方法,将对UML类图的处理单独抽离成一个类ClassGraph,然后在MyUmlInteraction交互类里实例化一个ClassGraph对象。所有关于UML类图的查询和计算都是在该对象里完成。

同时,为了更好地创建和使用Uml类、接口、属性、方法关联等类,我对提供的jar包中的类进行包装,构造了MyInterfaceClassMyUmlClassMyUmlInterfaceMyUmlOperationMyUmlAttributeMyUmlAssociation等类,通过将这些类相互组合,实现查询功能。

1.2 第二次UML作业

这次作业没有变动上次的总体架构,还是延续了在交互类里使用对象组合实现功能的办法。只是为了实现Uml状态图、Uml顺序图和模型有效性检查,我又新创建了三个类,分别是MyCollaborationChartMyStateMachineMyUmlStandardPreCheck,并通过UmlCollaborationInteractionMyUmlStateChartInteraction与外界进行交互。

具体结构如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
最后,以上三个部分,加上上次作业时间的类图部分,又通过对象组合的方式在MyGeneralUmlInteraction里实现。

2. 架构设计及OO方法理解的演进

2.1 第一单元

第一单元是表达式求导。由于在寒假的时候,我预习了JAVA,看完了Head first in JAVA这本书,所以对类的继承、接口的实现和一些简单的OO方法有所了解。所以我采用的是将类分成多项式、项和因子三层,并在因子层利用类继承和接口实现分出x幂、三角函数和常数项等因子类型。在第三次作业存在嵌套时,我采用了递归包含的方法,通过递归下降求导。

点击就送第一单元博客

2.2 第二单元

第二单元是电梯调度。其实在做完了这个单元后学习OS磁盘调度算法的时候,才感觉到两者又如此紧密的相通之处。

在写这次作业之前,我阅读了《设计模式》这一本经典书籍中的一部分内容。在理解了工厂模式后,我决定在这次作业中实践这个模式。

三次作业中我的架构大致如下图所示:(由于第三次作业架构最为完整,所以下图以第三次作业为例)

在这里插入图片描述
其中Factory就是我使用工厂模式的地方。通过对Factory指定不同的参数类型,可以创建foolcleververyClever三种不同的电梯(请原谅我zz的取名)。从电梯的名称就可以看出,三种电梯使用的调度策略是不同的,越clever,使用的调度策略的效率就越高。(其实这也是为我修bug的时候留下一条后路,如果复杂但是高效的电梯调度策略有bug,那么在bug修复的时候,将Factory的参数改一下即可换一种调度策略)

RequestParserMain线程(负责读输入)和Elevator之间的桥梁,在前两次作业中没有什么作用,但是在第三次作业中,它承担了分发请求的功能。

此次作业我个人认为做得最好的地方,就是把决策制定和存储请求的功能封装在电梯里的一个jobList类里。换言之,jobList是大脑,负责决策;Elevator是躯干,负责执行。所以只需要在电梯里实例化不同的jobList,即可实现不同的调度策略。

点击就送第二单元博客

2.3 第三单元

第三单元是JML的练习。这三次作业循序渐进,从第一二次单纯的图论,到第三次终于露出獠牙,进化为地铁系统。

这三次作业我的架构变化如下:

  1. 第一次作业的主要难点是对于distinctNode的处理。在我初次实现时,我只用了一个TreeSet去保存不同点的编号,如果删除一条路径,就把路径上的结点从TreeSet中删去。但是这回导致一个问题:当多条路径结点重叠时,这样处理就会导致distinctNode的结果比真实值小——因为删去一条路径不代表这条路径上所有的结点都应该被删去,因为可能改结点还存在于其他路径上。
    考虑到这种情况后,我该为用一个HashMap去记录distinctNode的情况。其中,key为node的编号,value为图中使用node的path的条数。当加入一条路径时,将路径上所有的node的value加1(如果之前不存在则在HashMap中创建node的key,并将value设置为1)。当删除一条路径时,将路径上所有结点的value减1,如果减1后的结果为0,则从HashMap中删去这个key。这样,当查询DistinctNode时,只需要返回HashMap中有多少个Key就可以了。
  2. 第二次作业,我为了增加架构的灵活性,使用了对象组合的方式而不是继承。具体来说,我的MyGraph类并没有选择继承上一次作业的MyPathContainer类,而是在MyGraph类中设置了一个私有的MyPathContainer类对象,用来实现有关路径的功能。
    同时,为了支持新增的功能,我将图的结构抽象成了一个GraphStructure的类,里面实现了图的构建和最小路径的计算等功能。同时在GraphStructure的实现中,我又将dijkstra算法的运算过程单独抽象成了一个类。这样能够使我的代码更加符合模块化设计的标准。
  3. 第三次作业的算法,较第二次作业而言,更加复杂。但经过一番思考后,我把这次作业新增加的功能:最小票价、最小换乘次数和最小不满意度都转化为了最短路径问题,统一使用dijkstra算法求解。
    由以上分析可知,由于几种要求都能够转化为最短路径问题,所以在设计架构时,我沿用了上一次作业的GraphStructure类,为其增加了一些适应这次作业的新功能,例如设置边的长度、拆点等等。计算最短路径的OriginGraph,最小票价的PriceGraph,最小换乘次数的TransferGraph和最小不满意度的UnpleasantGraph都继承自GraphStructure类,它们之间的区别在于边的权值不同。然后MySubwaySystem类中创建了originGraph, priceGraph, transferGraph和unpleasantGraph对象,用来实现对应的功能。具体的架构如下图所示:
    在这里插入图片描述
    其实这次作业,一开始我的设计并不是这样的。我第一次写的时候,将OriginGraph, PriceGraph, TransferGraph和UnpleasantGraph都写成不想关的类。由于它们之间的功能又很多重叠的地方,所以很多代码也是相同的。这就导致了代码量很大,而且维护的成本很高。我的第一个版本的作业写完后,一直有bug调不出来。考虑到由于架构设计的不好,找bug的成本太高,所以我决定重写一个版本,第二个版本将四个图结构相同的部分抽象出来,通过继承共用代码。虽然第二个版本刚写出来的时候也有bug,但因为架构简单明了,所以很快就把bug找出来并且更正了。这个经历告诉我,优秀的架构对实现、维护都有很大的帮助。

点击就送第三单元博客

2.4 第四单元

由于在上面已经叙述过,这里不再赘述。请详见这里

3. 测试理解与实践的演进

在前后四单元中,我强测出现过两次bug,互测出现过两次bug。

其中第一单元的第一次作业,由于省略-1*x的系数项时忘记处理*号,导致在一个测试点出了bug,并且互测时被刀了一次(作为报复,我刀了17刀)。所以在这次以后,我吸取了惨痛的教训,采用了极限编程+自写评测机的方式测试自己的程序。

所谓极限编程,即吸取了极限编程的一些思想,在写代码之前就构造可能错的测试样例。这样在写代码时,也会注意这些易错的地方,并且写完了也能用来测试自己程序的正确性(当然也能用来刀别人)。加上评测机随机生成数据的测试,基本上可以保证不会出错。在采用了这种方法之后,除了第一次UML作业因为某些其他事情没时间做大量的测试或者写评测机导致挂了强测点(QWQ),其他的作业没有出现过正确性的bug(除了有一次在互测中被大佬刀了CPU time tle)。

在JML单元过后,我又学到了一种测试方法:JUnit4。这种方法可以将代码查分成一个个单元进行测试,相比于评测机的黑箱测试,这种方法更利于找到bug位置,并且保证测试的完整性。

4. 课程收获

学习OO课的这一学期,我的收获大大超出了我之前的预想。具体来说,有以下的收获:

  1. 理解了防御性编程和测试的重要性。在学习上学期计组之前,我基本上没有什么测试自己程序的习惯,每次写完一个程序,就直接往评测机上提交,有bug再改。但在计组课程中,我都是通过自己手工造数据测试,从来没有尝试过写评测机。在OO课中,我为了保证程序的正确性,开始学习编写评测机,现在已经能很熟练地编写出一个评测机。
    同样,防御性编程的观念也是我在这门课中的收获。尤其是第一单元的作业,在wrong format的“折磨”下,我不得不考虑各种奇奇怪怪的错误输入,并保证我的程序能正确地识别错误的输入格式,并对正确的格式进行正确的运算。在这个单元,我深刻地理解了防御性编程的重要性;
  2. 从JAVA小白到能够轻松写出上千行的JAVA代码,学习并尝试了很多OO编程技巧。我非常赞同吴际老师在总结会上说到的观点:OO的概念必须通过练习才能掌握。上课听讲、阅读设计模式等经典书籍,起到的是将知识和前人宝贵经验灌输到我们脑中的作用,但是很多时候并不知其所以然。通过自己不断地踩坑、犯错,才能理解老师、书籍为什么要这么说。
    在这么多次作业中,我从只会使用类继承和接口实现,到开始尝试工厂模式,到开始学会用对象的组合代替类的继承。我的代码之间的耦合度也开始逐渐降低。两张图片可以清楚地表现出我在这方面的进步:
    这个是第一单元的第三次作业的方法耦合度分析:(只展示有问题的部分)
    在这里插入图片描述这个是第四单元第二次作业的方法耦合度分析:(只展示有问题的部分)
    在这里插入图片描述可以很明显地看出,第一单元的第三次作业中,我有很多方法存在严重的相互耦合的问题。但是到了最后一次编程作业,只有一个方法有这个问题。

  3. 学到了很多写代码之外的知识,例如JMLUML等。在OO开始将这些东西之前,我听都没有听说过这些东西。但是OO的神奇之处在于,可以通过上课、实验和课下作业,“逼着”我们快速掌握这些概念(果然ddl是第一生产力)。学习这些代码之外的东西,除了日常实用外,装X也是不错的

5. 课程的具体改进建议

  1. 建议在bug修复方面,强测和互测一视同仁。也就是说,既然互测可以通过bug合并将几个bug合并成一个bug,那么强测也应该允许bug合并。在我两次强测出问题作业中,都是犯了一个细节错误,改动都不会超过5行。但是在第二次强测出bug时,却不止挂了一个点,我觉得这是有失公允的。
  2. 建议老师上课讲的内容可以更接“地气”一些。这不是在说老师上课讲的内容不好,事实上,老师讲的东西都是相关领域的精华。但是就像一个孱弱的人吃补品吃多了反而有害一样,对一群连门都没入的新手讲一些非常高大上的东西,也很容易让同学们感觉云里雾里。
    我觉得老师可以将ppt分为两个部分,一个基础版,在课上讲,让大家入门;一个拓展版,由同学们自学,老师来答疑,并在实验课上考察。这样课堂上虽然没有将很多高大上的东西,但是同学们收获知识可能因为难度和广度的降低而增加很多。
  3. 建议OO网站增加允许查看历史通知、删帖的功能。
    现在OO网站的通知只能看一次,看完了之后就找不到了。但有些重要的通知可能看完了后忘记了,想要再次查看却是不能了。这个给我带来了很多次的麻烦;
    同时,目前在讨论区发言是不能删帖的。有时候问过一个问题后,发现有同学已经提过类似的问题,想要撤销这令人智熄的帖子,却发现不行。所以强烈建议增加一个允许删帖的功能。

最后,谢谢老师和助教这一学期的辛勤付出!
你们这一学期为OO课程所做的努力,我们都能够切身地感受到。说实话,在学这门课之前,由于往届学长学姐们的评价,我对OO课是没有什么好感的;但是随着学习OO的开始和深入,我发现往届学长学姐反映的问题已经大部分得到了完美的解决,课程的评价方式也变得非常公平而令人信服。因为这个学期我也担任了某门课的助教,我知道要做到课程的改革有多难。所以我对老师和助教们的付出感到由衷的敬佩。

猜你喜欢

转载自www.cnblogs.com/wsz1999/p/11071232.html