2023 Spring OO Blog
本单元所实践的正向建模与开发
正向建模与开发是只在工程开发中,先分析需求,然后设计整体架构,最后实现业务代码并完成后续测试。
在本单元作业中,主要体现在先画出UML类图、流程图、时序图等,设计出大体架构,然后完成代码。
由于直接用startUML
画图比较耗时,我一般选择先读懂题意然后用笔画出草图,在实现代码之后再进行完整的图绘制。以下是我的一个草图示例:
就我个人而言,其实以前几个单元的作业也是先画草图,再完成代码这样的一个粗糙的正向建模过程。就课程组要求的先画出完整的UML再进行代码实现我觉得还是比较难以实现的,一方面在实现中的改动和调整太多了;另一方面在第二第三次作业是迭代开发,然后加入了时序图、状态图的要求,本身在时间节点上就不是很正向了。。。其实也是明白课程组的良苦用心,实际中的工程开发确实也应该是这个流程,但是本身这个单元正确实现代码就已经很吃力了,所以本人还是选择了比较偷懒的方式,写完代码再画图。。。
本单元作业的架构设计
第一次作业
第一次作业我的架构非常简单,就只有
Library
和
Student
两个类,书本就用字符串表示了,书本在
Library
和
Student
之间完成
order
get
return
的交互就好。
第二次作业由于增加了校际借阅功能,我增加了
Book
类,相比单纯用字符串表示书本,可以更好的表示书本在校际之间的从属和借阅关系;同时,我增加了
Buffer
类,用于校际之间的书籍转运。
第三次作业在第二次作业的基础上基本上没有什么改变,就是在
Student
类中加入对每本书借入的时间记录以及是否超时的判断。
四个单元中的设计思维演进
这四个单元的学习和训练,确实大大提升了我的代码开发能力,有一种从生涩到熟练的感觉。具体来说,主要体现在代码整体架构设计方面。从刚开始第一单元只会学习往年博客来设计自己的代码架构,经过几次作业后,逐渐在写代码之前自己画出草图、构思出整体架构,对整体设计的把握有所提升。此外,我还更加注重整体设计中面向对象的设计思想,思考建哪些类、每个类负责什么、各个类如何交互,尽量保证各个类高内聚、低耦合;同时,我也学习了各个设计模式,在整体设计中遵循比如工厂模式等设计模式。
第一单元
- 总体来说,我的三次迭代开发比较顺利,也没有重构。
Expr-Term-Factor
结构解析语法,Polynomial-Monomial
结构进行计算。- 第一次作业搭建递归下降解析运算表达式的基本框架(其实我的程序也是支持多重括号的)。
- 第二次作业在第一次作业的基础上修改
Parser
和Lexer
,增加sinFactor
cosFactor
FuncFactor
并在Monomial中增加sinMap
cosMap
,从而支持含有新因子的表达式解析计算。此外利用了一个hashMap存储自定义函数定义,FuncFactor
中一个hashMap存储形参-实参的对应关系,从而实现自定义函数的调用。 - 第三次作业其实在第二次作业的基础上给每个类依据求导法则增加一个
derive()
方法就基本完成了,此外我还删除了一些冗余无用的方法或者属性,做了一点点优化。当然,利用递归的思想,我的程序也是支持多重求导的。
- 优化不足
第一次作业纯玩字符串游戏来优化,在最后得到的标准展开表达式∑coe*x**expX*y**expY*z**expZ
的基础上进行字符串的增删替换,最后在互测中出了bug。第二次作业没有去思考很好的优化策略,直接差不多放弃性能分了。第三次作业也只是修改了equal
方法的错误,实现合并同类项,并且没在最后玩字符串游戏了,而是在每个单项式转化成字符串的时候进行一些特判,但是因为中测一个点一直不过,推测应该是输出数据的合法性问题,还是关了一些优化。第二单元
三次迭代开发,我没有大规模的重构,每次大概增量开发200~300行,迭代体验还是比较好的。 - 三次作业中不变的东西
- 线程安全的思想 :要保护的东西是什么。三次作业中我都是使用
synchronized
关键字实现线程安全的。 - 避免死锁的思想 :首先是降低思维的复杂度,只在必要的时候使用锁,尽量避免锁的嵌套,该
notifyAll
的地方也要notifyAll
- 整体架构:输入线程——等待队列(第一次6个,后两次1个)——电梯线程
- 调度策略:模6法(第一次)/自由竞争(后两次)+ Look策略
- 三次作业中易变的东西
“易变的东西”,这是作业里要求的点,我觉得到没什么易变的东西,主要是根据迭代开发的题目要求来增加一些东西,并根据增加的东西来增加保证线程安全的相关代码。- 第二次作业中我增加了
eleMap
的动态增删功能;在Elevator
线程里增加了maintain
方法,实现了电梯维修后的乘客处理;修改了电梯线程结束的条件,维护了unSent
这一变量。 - 第三次作业中我增加了
Elevator
关于可达性的各个属性;增加了邻接矩阵和RoutePlan
来实现根据当前状态实现路径规划;在开关门的时候增加了很多限制判断,来实现只接人电梯数目和同时开门电梯数目的要求,多维护了openNum
和inNum
。
- 对于多线程的理解
第一次写多线程的时候连多线程是什么都不知道就一通乱写。后来在助教学长的建议下阅读《图解JAVA多线程》,方才窥得多线程设计的奥秘。在这单元的学习中,我学会了同步互斥机制,掌握了许多同步互斥的方法,弄明白了多线程到底是个什么东西。 - 整体设计的思维
在写一次作业之前需要想明白。我要设计哪些线程?线程间的共享对象是什么?我要怎么保护共享对象?大致想清楚了之后再结合SOLID
原则调整,尽量简化思维。(其实在这个单元尤其是后面两次作业中我很有体会,避免死锁还有一个很重要的方法就是在设计之前就简化你的思维复杂度,而不是写完之后在垃圾堆上各种加锁打补丁,那样往往会造成意料之外的bug)第三单元
- 一个是对算法复杂度有了更深的理解(虽然课程组说本单元的重点不在算法上,但我收获最大的点在算法)。首先我学会了并查集的基本操作以及并查集的按秩排序优化。其次我学会了朴素Dijsktra的优先队列优化、“魔改”优化。我还学会了用动态维护来降低整个程序的
cpu time
开销。因为最近做的frb也跟算法优化有关,在跟同学的交流中,以前对算法时间复杂度没什么概念,现在可以准确分析算法的复杂度,并思考如何优化。 - 另一个是体会到规格与实现确实需要分离,作业层面就是纯按着规格朴素地写会T掉,实际应用层面就是如果设计和规格不做好分离,会使得程序的性能和可拓展性都很差,不是一种很好的软件设计实现。
- 最后一点收获就是关于测试。以前对各种测试没有概念,现在才知道我在不知不觉中实现了黑盒测试、集成测试、压力测试。每次作业我都是高强度测试,这次hw11纯属是测出问题了心里烦躁不想改,重写了简单的慢方法造成了T,强测全对的记录就此打破,悔不当初,其实下来捏了十来行数据就de出来了,修改两个角标就对了。
第四单元
认识到正向建模开发思想的重要性,先画好相关设计图再进行代码开发。四个单元的测试思维演进
其实就实际而言,测试思维我并没有什么演进,甚至和上个学期的CO的测试思路一样特殊数据+随机数据。具体而言,我的测试一般分为两个步骤: - 手捏一些基本功能数据,测试基本功能的实现是否有问题(这个也可以用指导书后面的样例数据,不过样例数据可能比较弱)。
- 大量随机数据进行高强度测试,这里主要依靠各位大佬的评测机。
除此之外,我在第三单元学习到了回归测试、白箱测试、压力测试等等,也将压力测试、回归测试用于了我后续的程序测试中。课程收获
- 大大提升了java编程能力
- 掌握面向对象设计思想,而不是以前只会单纯的面向过程
- 学习到了各种设计模式,比如工厂模式、生产者消费者模式
- 掌握多线程编程,以前半点不会多线程,也想不明白,学明白之后,如何设计线程(什么模型)、如何保护线程安全还是很有意思的
- 学会递归下降算法
- 学会绘制UML类图、时序图、状态图
- 学会阅读JML并了解JML语法
- 提升了代码阅读能力,在试图hack他人的时候,前几次是有把代码下下来阅读的。先梳理这份代码的整体架构,再看这份代码的实现细节,阅读代码能力变强了。
- 博客撰写能力增强,每个单元自己写完博客,也会随机拜读他人博客,学习他人优秀的书写方式。
- 测试能力增强了,OO作业基本上需要比较强的测试才能发现强测之外的bug,每次为了保证强测、互测不出问题,我都进行了高强度测试
- 增加了抗压能力,总是想着OO这种只用课下完成就好的作业,那肯定得弄好,所以花费了比较多的时间,每次高强度测试、测出bug再修,压力挺大的。甚至为OO熬了第一个通宵,抗压能力大大提升。
- 展示自我能力提升,我是一个比较内向的人,在OO课程中我不但在讨论区进行分享、回帖,还进行了研讨课展示,迈出了跟他人在公共区域交流以及自我方法观点展示的第一步。