面向对象程序设计第四单元总结
面向对象第四单元总结
一、Unit 4分析总结
本单元作业基于UML的模型化设计,建立了一个支持三种UML图的解析器,并具有有效性检查功能。这单元的第一次作业是历次最令我无从下手的一次,整个单元的核心在于读懂UML图所包含的内容,弄清楚UmlElements之间的关系,才能在此基础上布置出良好稳定的架构。
1. 第一次作业分析
本次作业需要实现对UML类图的解析,看似简洁但需要大体构建出整个单元的框架(后几次作业几乎没有大的重构,只是在其基础上添加功能)。刚开始的时候有些棘手,如今看来主要思路有以下两个方面:
-
解析的元素有什么
需要我们从已有的UML模型中的元素入手,结合官方代码中的
UmlElement,将实际的模型与类图中的各种元素建立对应关系,掌握每个子类代表的意义; -
解析器需要做什么
这里我们要从需求入手,仔细阅读解析器支持的指令内容,弄懂我们需要记录、整合、操作哪些元素,例如:查询类关联的对端是哪些类时,首先应记录所有的
UMLClass,其次需要整合类与类之间的联系,这就要求我们追踪association关联关系。进一步,结合处理过的mdj文件,对应编写代码的思路就会更加清晰。
2. 第二次作业分析
本次作业在第一次基础上加入了UML协作图和UML状态图的支持,并添加了六条指令。具体的学习和编写代码的思路与第一次类似,还是跟随教程学习规范UML图,并阅读官方包代码,分析具体指令内容三个方面。
值得一说的是,为了不将大部分代码堆叠在主解析器类中,我将代码结构做出了如下变化:
- 将自己创建的辅助
UmlElements们放入了一个elements包中; - 将原解析器类中的解析UML元素的代码放入了一个工具包
util中的Parser类,并将最终解析完毕的四个对象:UmlClass类对象HashMap,UmlInterface接口对象HashMap,UmlInteraction顺序图对象HashMap,UmlStateMachine状态机对象HashMap作为全局静态变量供主解析器类访问。
在做出如上改动后,主解析器类中只剩下与查询指令相关的代码,各个类不会出现冗杂过长的结构,使得整体更加可读。
3. 第三次作业分析
第三次作业添加了模型有效性检查功能。针对每一个规则,分析其对哪些元素和哪些行为进行了规范,需要对架构有一定的修改。延续第二次作业的结构,我在util包中新加入Checker类,并通过静态方法来完成查询操作。完成检查工作的同时也进一步加深了对UML图的理解。
- 代码行数:

- 类图:

4. 第四单元总结
本单元作业对于层次化、规格化、模型化均有一定的涉及,可以算是对本学期OO生涯的完结。在完成作业的过程中,既需要阅读官方代码,也需要自己思考类之间的组织关系,运用到了许多之前出现过的图算法,几乎所有代码都是由学生自行完成,对面向对象程序设计的能力有较大提升。
美中不足的是本次作业中出现了许多不明确的细节问题,希望课程组能对指导书进行进一步的优化,将目标内容解释的更加清晰,多使用表格、图形来描述,提高可读性,而不是单一通过加粗和缩进。本单元的官方代码是最为复杂的一次,在阅读上有一定的难度,但可以从中学会一些方法。
二、各单元架构设计与方法理解
1. 第一单元
第一单元目标是实现较为复杂的可嵌套表达式求导。有一说一,第一单元的递进难度和重构规模相对于后几单元甚至更高一些,好在代码编写水平通过Pre的训练有了一定的提升,因此在面对第一次作业时还比较顺手。第一单元是互测最积极的单元,通过学习同屋同学的代码,观摩别人的思路和架构,对于我自己的理解有了很多补充,也认识到了许多我没有考虑周全的地方。
主要难点在于:
- 思考一个良好的类逻辑:表达式类、项、因子、加类等,好的架构会对代码逻辑和性能都有较大的提升。综合下来,可以选择树形结构存储,也可以按照表达式—项—因子的递进关系来存储。并在结构上可以进一步做出许多优化:删去0项,合并简单的同类项等,以及最后的化简输出。
- 递归下降:是用于解析表达式的较好的方法,在网上可以找到一些资料和模板供学习,但是其核心思想需要有一定程度的理解。
2. 第二单元
第二单元目标是实现多线程电梯运行系统。在写作业之前,我练习了有关sychronized与notifyAll之间的相互操作,对于Java中的多线程逻辑有了一定的理解。在编写代码时,主要考虑总等待队列、调度器、电梯之间的三层次架构,为了防止死锁的出现,我规定下层类不能访问上层类的变量。由于LOOK算法性能较好,每次作业的性能分还比较高,但第三次作业强行换乘的一些操作不是很符合逻辑,有待改进。
主要难点在于:
- 整理出良好的电梯逻辑结构:有的同学选择多部电梯争抢一个等待队列,有的选择加入调度器类进行分配;多种方法都可以满足需求,重要的是避免死锁和轮询操作,实现正确可靠的电梯调度。
- 调度算法优化:第一次作业使用LOOK算法已经可以满足性能要求;第二次作业
morning的性能较低,我一直特别好奇大家都是对morning选择什么策略;第三次作业的优化有点画蛇添足的感觉,并没有强制换乘的情况,因此使得我处在:向上优化太复杂,简单优化没屁用的尴尬局面。
第二单元的训练和上机板块中,还学习到了生产者——消费者模式、工厂模式、单例模式等多种Java中常见的设计模式,有着相当大的帮助。
3. 第三单元
第三单元是基于JML规格,实现多人网络社交系统。本次作业需要预先学习和熟练JML规格设计语言。整个编写代码的过程大概是在:阅读JML规格——整理需求——翻译成Java语言——对性能做出优化。后两单元的作业主要是在满足在某种数据存储架构下,对其访问、查询、修改等不同指令的操作,由于数据类型比较相似,因此几乎都可以选用HashMap存储,在此基础上进一步完善图结构。
主要难点在于:
- 阅读JML规格,并对整体代码需求有一定的把握,在此基础上才能更好的实现需求。
- 提升性能的算法改进:如堆优化的迪杰斯特拉、并查集等,学习了一些在Java中常用的图算法模板。
- 对细节的把控:许多指令虽然简单,但就其逻辑上需要保证JML规格的严密,因此各种判断条件一定要梳理清楚,否则会出现非常低级的错误。
4. 第四单元
前文已经提到,故略
三、各单元测试与实践理解
1. 第一单元
第一单元编写测试不算太复杂,可以通过Python的包来获得标答和格式检查。借助室友大佬编写的评测机,可以实现大规模、较高复杂度的数据生成、自动化测试、反馈的功能,同时也学习到了许多在Python中的知识,对递归下降有了更深刻的理解。
第一单元比较适合加断点调试,这个方法在de递归下降的bug时尤其有用,可以可视化当前字符串解析进度,跟踪每个函数的进一步执行。因此,在调试过程中大大增加了对IDEA的操作熟练度。
2. 第二单元
第二单元由于多线程特性,在本地测试难度较大,经常有同学出现本地跑十次一次没错,提交上去就裂开的情形。不仅如此,在输出数据的合理性检查也有一定的难度,实在是没精力在用啥语言写个测试程序。因此,第二单元作业主要选择一些小规模、具有代表性的数据之间测试,这种方法可以帮助寻找电梯调度算法的问题:例如转向异常,开关门异常等等。对于同步问题,仍需要形式验证来稳固了。
多线程调试方法,有同学在研讨课上分享了一些监控代码的插件,对于代码程序性能、CPU占用、死锁等都有一定的监控能力,可以动态的看到代码底层的执行顺序,对于理解多线程、编写多线程有很大的帮助。最重要的是,我认为学习多线程,更应该关注的在于多线程架构的交互,理解底层代码顺序,考察自己的代码在多线程下的表现——如何避免死锁、如何提高CPU效率、可视化对比不同架构带来的不同表现……而不应该把深入学习的重心放在逻辑性上并不是那么强的性能分上。希望课程组能够进一步引导同学们对多线程更深入的学习和思考,从性能分的局限中跳出来,相信更多同学会有能力有激情投入到其中。
3. 第三单元
第三单元测试数据体量较大、指令种类较多,我水平不支持我写出美观的评测机,因此只能以形式化验证为主,覆盖部分指令数据为辅的方式测试。本单元深刻体会到了覆盖性测试的重要性,实在不能偷懒,否则就会像我一样犯下age / people.size()忘判断空的情况,强测直接裂开,追悔莫及。
本次作业只通过编写评测机测试了可能出现复杂度较高算法TLE的情形:编写程序生成万条最复杂的指令并反馈CPU运行时间,保证满足时间限制。
4. 第四单元
第四单元测试数据可以通过StarUML手动建模——工具包导出数据——运行评测的方式,虽然有些繁琐,但还是属于可以把握的范畴。我针对每个指令和有效性检查的规则,模拟了一些可能出错的边界数据进行测试。有些遗憾的是许多规格在指导书中并没有直接说清楚,因此需要不断改进。
本单元对于良好的图算法有了进一步的理解,算是补上了第三单元偷的懒。寻找环、寻找联通路径等,对Java中其他数据结构如:Stack、LinkedList、Queue等也有了较为熟练的运用。
四、课程收获
OO课程转眼间过去,一看文件夹已经有长长一面的历次Homework,现在再回想起来一时感慨万千。在写本次博客总结时,我翻看了从寒假的Pre一直到最后一次作业的代码,明显感觉到自己的代码风格、格式、类的组织、美观性等都有了显著的提升:从Pre冗杂、拼凑、高度耦合的代码,到如今逻辑更加清晰,类与类各司其职,不得不说经过一学期的面向对象程序设计训练,我有了很大的收获。
- 通过每单元作业前序知识的准备,我学习到了许多面向对象的核心内容:层次化设计、多线程设计、规格化设计与JML语言、模型化设计与UML图。应该深刻领悟其中蕴含的思想并融合到自己编写代码的习惯中去。
- 通过每单元的上机训练,我学习到了与每单元核心内容相辅相成的知识:Java的多种设计模式、JML语言的编写、UML类图的理解等,都对作业内容进行了一定的扩展和加深。
- 通过每单元同学们的研讨分享,我可以集大家之所长,相互交流提升,查漏补缺。
- 通过每单元最重要的作业,我以实践的方式真正接触面向对象思想,感悟代码的运行,其中的许多:方法实现方式的权衡、类架构的取舍、修改与重构等,都为以后在面对实际问题时打下了稳固的基础。
官方的话就说这么多,面向对象程序设计的魅力远远不止这些,OO课只是我们不断学习路上的开始。在今后学习生活中,我们仍需要保持热情,充分利用学习到的方法,进一步印证与思考,才能最大程度的提高自身的能力。
五、改进建议
- 希望课程组能够设立不同于性能分的措施来调动同学们进一步探索的热情。性能分只能作为学习水平高低的一个小方面的体现,但教学初衷应该是引导同学们的思维。在多线程、JML、UML单元,可以设立一些其他的目标或可探索的内容来引导大家在满足测试要求下的强化学习。
- 课程组可以适当为同学们提出一些编写评测机的方法和思路,或者开设类似的讨论区引导同学们自己学习:可以运用其他语言、可以学习某些高效的方法。对于我来说,适当的引导会让我对测试方面有更为浓厚的兴趣。
- 希望进一步增强课程网页讨论区的优化:第三四单元细节较多时,讨论区盖楼太过严重,可读性有待提高。
- 希望指导书的规范性、美观性都能做出一定的提升:尤其是针对部分描述不清的歧义、在
markdown中使用表格来规范一些类似于指令、规格的操作其实更加可读,而不是单一的使用缩进和加粗。

浙公网安备 33010602011771号