架构设计
第一次作业
功能实现
- 按要求,设定
BookShelf
,BorrowReturnOffice
,AppointmentOffice
类
实例化书架、借还处、预约处。
其中,借还处内置与BookShelf的联系,用于在每日闭馆时将图书还至书架;预约处同样内置与BookShelf的联系,用于按照预约要求,将书架上的书移至预约处,同时将逾期未去的书还至书架 - 设置
RecordBook
类,记录书籍送至预约处时的时间,实现逾期清除的功能。 - 设置
Reader
类,实例化读者,记录读者借阅的书籍。 - 设置
Manager
类,供MainClass调用,管理图书馆中的所有属性:书架、借还处、预约处、所有读者。
相关优化
AppointmentOffice
中。记录图书预约请求的requests
,记录送至预约处的图书records
类,容器均为LinkedList
。这样在首元素的删除、尾元素的增删时效率较高- 在
addOrderRequest
时,采取筛选策略。即若requests
中存在与新增orderRequest相同的请求(即预约书籍相同、预约学号相同),那么就不予加入,忽略该预定请求
大致思路
UML类图如下
第二次作业
功能实现
- 新增书籍归还是否逾期的检查,用
RecordBook
记录Reader
借书的日期,根据还书日期判断是否逾期 - 新增续借功能,在续借时将
Reader
类中RecordBook
记录的借书日期加上30天 - 新增图书漂流,设置
DriftCorner
类,当有人捐赠图书时,将其送至漂流角;当有借阅漂流角图书的请求时,起到第一次作业中BookShelf
的作用 - 新增图书转正功能,在
BorrowReturnOffice
类中添加计数器counts
,以非正式书籍的书号为键值对,记录其被读者归还的次数。若在闭馆整理后,借阅次数 >= 2,则将该非正式书籍的书号转正,送至BookShelf
。否则,送回至DriftCorner
大致思路
UML类图如下
第三次作业
功能实现
- 新增对预定的限制,若用户存在对某B类书正在生效的预约,则该用户对于B类书的预约一定失败;若用户存在对某书号C类书正在生效的预约,则该用户对于该书号C类书的预约一定失败。在
AppointmentOffice
类中,实现bOrderInForce
,cOrderInForce
方法,遍历requests
与records
,查询对该用户是否存在相关的正在生效的预约 - 新增读者的信誉积分
- 读者信誉积分为负,则借阅、续借、预定操作均失败(借阅失败时,书籍仍在借还处)
- 读者信誉积分的增减(20为上限,无下限)
- 开馆时,实现在规定期限内还书、捐赠书籍的加分
- 闭馆后,检查用户是否按期还书,用户是否取走
AppointmentOffice
中送达的图书,图书转正。在操作时应先减后加
大致思路
UML类图如下
代码设计与UML的关系
-
类与代码文件的对应关系
- 每个UML类会映射到代码中单独的类文件。以三次迭代后的UML图为例,其中的Manager类映射到代码里的
Manager
类 - UML类中的属性
attribute
转化为代码中类的成员变量,这些成员变量的类型和访问修饰符与UML中的属性相对应。如{readOnly}
对应final
字段 - UML类中的方法
operation
转化为代码中类的方法,方法的参数、返回类型与UML中的方法相对应。如+
对应public
,-
对应private
- 每个UML类会映射到代码中单独的类文件。以三次迭代后的UML图为例,其中的Manager类映射到代码里的
-
类与关系的转化。如果在UML类图中存在某种关系,那么在代码设计中也应该相应地实现这种关系
- 关联关系:在一个类中使用另一个类的实例。如
Manager
类使用BookShelf
,BorrowReturnOffice
,AppointmentOffice
等类的实例,在UML图中均存在相应的关系 - 依赖关系:一个类的实现依赖于另一个类。如
AppointmentOffice
类的实现依赖于BookShelf
类,则在UML图中存在相应的关系 - 继承关系,接口和抽象类:此单元中均未使用,便不再赘述
- 关联关系:在一个类中使用另一个类的实例。如
正向建模与开发
此单元要求完成作业时应先做好相应的设计,绘制UML类图后再实现具体代码,即在开始相关的代码开发之前,首先进行系统的需求分析,并使用StarUML工具创建UML模型。随着代码迭代,对图的要求从类图,扩展到状态图、时序图,用于更好地描述系统的结构和行为。
然而,由于实现的差异及思路的更新,若想在动手前便将迭代后代码的架构用UML图全面地、清晰地展现,这显然是有难度的。因此,在迭代时,可以先画出一个大致的UML类图,标明相应的关联、依赖等关系,而将具体需要实现的类与属性省略。在进行开发时再根据代码对UML类图进行更改,以保持代码与UML类图之间的一致性。
四个单元中思维的演进
架构设计思维
第一单元,借鉴了公众号推送中的代码,再结合实验课给出的代码示例,进行第一次迭代的开发,可谓摸着石头过河。由此初步理解了对递归下降的含义,在之后的两次迭代中通过与同学交流沟通、同时参考往届博客,能较为独立地实现相应的功能,不做代码层次的参考借鉴。
第二单元,由于对多线程相关概念及实现机制的陌生,也是根据实验课给出的代码进行修改,在此基础上勉强完成第一次迭代。对于后续的分配乘客、重置电梯等,由于对多线程的逐渐熟悉,能够自主完成相应的迭代开发,而不借鉴参考他人方法。由于是自己的设计,导致此单元后两次作业的性能不是很强。
第三单元,在第一次迭代时完全按照JML语言实现相应接口,然而后续发现时间复杂度太高的问题,因此在与他人的沟通交流后,对时间复杂度较高的方法动态维护。第一次迭代由于实现细节的疏忽导致强测很差,在后续的迭代中实现较为完善。
第四单元,和oopre的冒险者有些类似,在经历oo正课的磨炼之后,能够游刃有余地进行架构设计,私以为是符合面向对象这一宗旨的。且功能划分、实现细节相较oopre而言提高了很多。
测试思维
在第一单元第一次迭代时,编写python代码进行相关测试,由于第一次迭代的数据生成、正确性检验较为容易,较为轻松便能完成。而在第二次迭代及之后,都用到DPO进行测试(不得不说是真好用)。
但在第三单元第一次迭代时,DPO的数据生成不是很严谨,导致许多操作失败,而生成的图不是很复杂,测不出代码时间开销大这一问题,第一次迭代的强测也因此挂掉。在第三单元后两次迭代,又开始搭建评测机,保证数据生成合法(即不失败)的情况下,使图在强测的数据量范围内尽可能复杂,以测试代码的正确性与性能。
课程收获
- 基本了解面向对象思想,掌握了搭建框架的能力
- 对评测机的数据生成、正确性检验初步掌握;能造出一些极端样例用于互测刀人
- 理解并掌握了递归下降、多线程的思想和实现方法,了解JML、UML语言
- 熟悉Java语言,对Java常见的容器和一些算法总结出自己的心得
- 锻炼心态