OO第四单元总结
\(\mathcal{Author:gpf}\)
源码见 https://github.com/solor-wind/BUAA_OO
正向建模与开发
事实上,在前三个单元的作业中,已经涉及了正向建模相关内容,只是还没有强制要求或者细节不到位。比如每个单元的第一次作业都要先想好一个拓展性较好的架构再开始写代码。而在这一单元中,正向建模更加突出。
在开始这一单元的作业时,首先绘制的是一个程序架构,在草稿纸上列出要实现的功能、可能要拓展的功能,然后将一些功能或属性封装起来成为类,大致确定有几个类以及每个类大致的功能和属性。比如图书馆类需要管理各种书籍以及借书处等存放书籍的地方、书籍本身并不需要建类因为官方包的
BookId
已经足够完善。
然后,就可以在StarUML上绘制类图、状态图、顺序图了。但因为对UML的不熟悉,导致画图进程较慢而且容易出错。再加上之前只是形成了一个大致的架构,因此经常要修改属性和方法。在这一步骤中耗费了很多时间。
- 类图:展现各个类的属性与方法、个各类之间的联系。主要纵向关系有泛化与实现,横向关系有依赖、关联、聚合、组合
- 状态图:述对象的状态和状态之间的转换。
- 顺序图:展示了对象之间的消息传递顺序,以及消息传递的时序关系。
最后,就可以对照UML写代码了,由于架构、属性方法都已经建好,基本只需要无脑填写就好了。在一些细节的地方比如类的返回值、更改了两个类之间的调用方法的时候,还要及时修改UML中对应的地方。
架构设计
这一单元的作业总体难度比前三个单元都简单一些,最终用了532行完成(去掉空行和注释共483行)
复杂度分析如下
类图如下
本单元的核心功能就是对书和人的管理,因此类的设计应当围绕书和人来设计。书的类由官方包提供,而人的属性则需要封装起来单独建立一个类,图书馆负责对书和人的管理。
书出现的地方主要有:书架、借还处、预约处、漂流书架、人
因为对每个地方的操作如查询本数等等并不复杂,同时还要经常修改这些地方的书,因此我选择将其放在图书馆类内部,用
HashMap
来代表每个地方的书籍。但从长远来看,如果要对每个地方添加新的功能,则需要单独建类来保持程序架构的清晰、简洁。
整理
既在开馆时进行整理(开馆整理前先更新时间),也在闭馆时进行整理,实现函数为
organize
整理按如下次序进行:
- 检查每个人是否有逾期的借阅书籍并进行扣分
- 检查是否有逾期的预约并进行扣分,若为开馆整理则进行移动
- 将借阅处的书籍移动到书架或漂流角,并进行加分(若有)
- 处理尚未完成的预约
处理请求
总体先用 dealRequest
进行分类,然后进入具体方法执行重点为借阅、预约两条指令。
借阅
先将要借阅的书分为漂流角和书架两类,然后按照A类书、B类书、信用分查找是否满足条件。对应方法为
borrow
预约
先判断信用分、是否是漂流角书籍,然后按条件检查是否能借阅。能则加入到预约队列中,即
LinkedList<String> logP,LinkedList<LibraryBookId> logB
。同时,预约处已经存在的书籍以
LinkedList<LibraryBookId> aoBook
等类型的容器存储信息。预约的对应方法为 order
读者
HashMap<LibraryBookId, LocalDate> books
存储当前读者借阅的书籍以及对应逾期时间,方便进行逾期判断与处理。
代码与UML
由于遵循了先UML后代码的顺序,最终UML模型和最终的代码设计基本一致。
OO课程架构设计思维
OO第一单元:层次化设计的思想的应用和工程实现将其——递归下降解析表达式
- 通过单元训练理解了递归下降的架构和层次化设计思想
- 通过第二次作业的重构真正运用了层次化设计思想
OO第二单元:多线程的设计方法——模拟多线程实时电梯系统
- 通过第五次作业学习了多线程的编写方法
- 通过第六、七次作业学习了电梯的调度方法、死锁避免与处理方法
OO第三单元:JML规格理解与代码实现——实现简单社交关系的模拟和查询
- 学习了JML
- 实践了Junit等各种测试方法
OO第四单元:正项建模与开发——使用UML设计图书馆系统
- 学习了UML中类图、状态图、顺序图的制作方法
- 领悟了正向建模对较大代码量程序设计的帮助
OO课程测试思维
很幸运在课程中通过了每一次强测和互测。
在课程中,也学到并运用了许多测试思维,编写了评测机。事实证明,下面的每种方法都必不可少。评测机源码见BUAA_OO_TEST
静态分析
个人在这方面的做法主要包括两方面:
- 逐条比对指导书。写完代码后,将指导书每一行都阅读一遍,确保没有缺少功能/错误实现功能
- 逐行分析代码。将代码的每行阅读一遍,确保每一行、每个方法都达到了目的。
- 白箱测试。主要针对互测环节,阅读他人代码寻找bug
动态测试
这部分收获最大,主要是与zx一同完成了覆盖每次作业的功能较为完善的评测机。在编写评测机的过程中,无论负责数据生成还是正确性检验,事实上都要求对指导书仔细理解,确保不会遗漏各种情况,也因此经常会出现边改评测机边改自己代码的情况。
- 黑箱测试。按指导书数据限制,以一定比例生成尽量全覆盖的数据,并进行正确性检验。
- 压力测试。针对指导书的边界限制条件和特殊情况,构造有针对性的数据。如第一单元的exp(0)、第二单元在第50秒给出70条指令等等。大部分都需要手动构造。
OO课程收获
代码量
作业 | 含注释与空行 | 不含注释与空行 |
---|---|---|
hw3 | 775 | 679 |
test3 | 504 | 385 |
hw7 | 1236 | 1091 |
test7 | 477 | 397 |
hw11(除去官方包) | 1604 | 1407 |
test11 | 1470 | 1325 |
hw15 | 532 | 483 |
test15 | 933 | 843 |
hw为作业,test为评测机(和zx一起完成)
OO课程应该是上大学以来代码量最大的一门课程了。对比来看,大一下的数据结构大作业只有325行(含注释与空行),大二上的计组最终写了1622行(含注释与空行),OOpre最终写了1328行(无注释与空行1102)。从这里就可以看出,OO成功训练出了我们短时间内写出大量高质量代码(或者屎山)的能力,真的让我受益匪浅
架构与重构
总共4个单元,每个单元的三次迭代都添加了意想不到的功能,这对架构设计是十分严苛的考验,但也逼迫我学会了先设计架构再写代码、提前思考功能并预留拓展性的能力。以第一单元为例,由于第一次作业仅为多项式结构,并不设计嵌套单元,因此在架构层面偷懒。结果第二次作业的exp就让我苦不堪言,思考了好几天才重构出一个可以存储、运算的架构。
建议
- 希望能开放评测机的运行环境、硬件设备等信息,方便进行测试。或者改变评测机运行方式,不是高强度并发而是分散均匀测试。
- 适当放宽代码风格检查的限制,比如“不能使用形如import*”这一条对建立软件包来说很不友好
- 后两个单元可以放一些其他内容,或者改进junit评测和顺序图评测、减少指导书修改次数
致谢
感谢助教们的辛勤付出,让我的代码能力得到极大提升。感谢我周围的同学们,对我顺利完成作业提供了很多帮助。感谢Hyggge,OO前两个单元的领路人。
结语
OO结束了,但以程序员生涯的视角来看,它并没有结束,甚至不是结束的开始,而只是开始的结束。