面向对象设计与构造第四单元总结

  • 总结本单元所实践的正向建模与开发
  • 总结本单元作业的架构设计,并对比分析最终的代码设计和UML模型设计之间的追踪关系
  • 总结自己在四个单元中架构设计思维的演进
  • 总结自己在四个单元中测试思维的演进
  • 总结自己的课程收获

作业要求

  • 本单元第一次作业以一个图书馆模拟系统为例,锻炼同学们对程序架构的设计能力,以及加强对 UML 类图的绘制训练
  • 本单元第二次作业以多学校的联网图书馆模拟系统为例,锻炼同学们对程序架构的抽象能力,以及加强对 UML 状态图的绘制训练
  • 本单元第三次作业以前两次作业为基础,锻炼同学们对 UML 顺序图的绘制训练

总的来说,我们在第一次作业实现了一个图书馆的基础功能(借阅、预定、书目数量限制、还书、损毁&修复、丢失等),功能难点主要围绕借阅无书时的预定环节。在第二次作业中,我们将单个图书馆的功能封装,并提升为多个,并加入了校际借阅流程与无书购买流程,难点主要在闭馆后对不能立刻处理的借书请求的分类处理&处理顺序,整理日的动作顺序&购书操作,学生获取到一本书籍后对预约/校际借阅/预购队列产生的影响。在第三次作业中,增添了逾期还书的处理方式,对程序主干逻辑没有过多变动。

在程序之外,本单元重点训练了 UML 类图、状态图和顺序图的绘制,并分别在三次作业中进行了考察。

类图针对程序代码中所有的类。状态图针对一本书在借阅过程中发生的状态转移。顺序图针对预定成功到成功取书之间程序的调用关系与顺序。

正向建模与开发

单元第一次作业实现单机图书馆的构建。我将图书馆各个部门分装为静态类,将输出功能和日期转换功能封装为工具类,将书籍、学生和借阅请求封装为类,在主类中进行图书馆功能的分发与实现。

过程中遇到的问题主要在学生获取书籍后要对预约队列进行刷新,需要一些容器操作。

单元第二次作业将图书馆变为联机图书馆。首先将原本代表部门的类从静态类转换为一般类,便于每个学校分别 new 一个对应的部门进行处理;然后将原本主类的逻辑封装为一个 School 类,代表一个学校的图书馆,再在主类创建一个图书馆的容器进行存放。其他类模型未发生改变。当接受请求后,先获取所在图书馆,再分发到对应图书馆执行相应功能函数,完成请求功能。

问题主要集中在请求分类流程:当一个请求不能实时满足,需要在闭馆后统一进行处理,并根据书籍余量、状态判断是校际借阅、校内预定或校内购买。指导书在此的说明不够详细,前后要求还有改动,所以这部分完成的不是很顺利。主要还是与第一次的处理逻辑不同,导致了架构修改上的困难。

单元第三次作业更像是补偿性作业,上次一作业难度过高导致这一次作业的内容就相对较少,只需要新增并维护书籍的一个字段即可,并在借还时更新字段,调用相应方法。

UML模型设计

以第三次作业为例,对比分析最终的代码设计和UML模型设计之间的追踪关系。本次作业类图如下:

Main

程序核心为 School 类,它作为包含结构、处理请求的基底存在,包含多个字段和方法。

其左侧的是学校内含有的各个部门,它们在 School 类内的方法调用中出现,接收响应请求并处理,图中调用输出类 PrintAction 进行统一规格化输出。

School 类右下侧的是学校包含的学生、书籍、请求。它们也在方法中被调用,完成相应属性、状态的转换。

第三次作业顺序图如下:

SequenceDiagram1

消息 1-10 是评测要求出现的从预定成功到获取书籍用到的顺序逻辑,再下面是其他正常需要用到的功能逻辑。 Main 类通过调用 School 类中的处理方法,实现对请求的初步处理,在处理方法中,School 类又利用自身字段进行具体的业务逻辑实现。

架构设计思维的演进

第一单元:递归下降与表达式处理

在第一单元,由于不了解层次化与架构的设计方式,课程组安排了多项式作为训练内容,它半强制地让我们使用层次化的程序结构进行编程,以此来加深我们对层次化设计的印象。层次化设计、递归下降和化简运算是本单元的重难点,也拉开了oo课程的帷幕。(性能分从这里开始卷烂)

第二单元:多线程设计与电梯调度

第二单元,在我们已经初步了解层次化设计后,采用了多线程的方式进行考察。一方面,对共享数据的线程安全、多线程锁的应用等方面进行了考察;另一方面,电梯运行逻、请求分配、拆分调度等内部逻辑也是需要考虑的重点。我在本单元采用了黑板模式进行设计,中心黑板为调度器,通过单向的数据访问确保了线程安全;使用过程模拟来将请求分配到合适的电梯中。途中虽然遇到了诸多问题,第三次作业还出现了修到最后一刻也没修完的 bug,我还是觉得这是面向对象课程中设计最成功的一个单元。

第三单元:JML 契约与社交网络模拟

第三单元中,我们了解了一种表述 Java 程序需求的语言模型 JML。它通过格式化的要求,约定了需求提出者与程序实现者之间的契约。我们在 JML 的基础上进行了程序设计,模拟了一个社交网络,实现了与其相关的数据指标计算。很遗憾本单元在实现上偏离了 JML 单元设计的核心,而更注重了在执行需求下的程序性能,不幸地将 JML 单元变成了惨烈的算法单元。虽然这个单元的得分要比开始的两个单元要高,但是过程中的设计体验和实现过程并不如前者。

第四单元:UML 模型与图书馆系统模拟

第四单元,我们详细介绍了 UML 图与其对设计的引导作用。作为设计中十分重要的一环,绘制出 UML 类图对程序中类的设计、管理都有十分重要的作用。本单元以考察 UML 图的设计、程序功能实现为核心,在架构上并不做严格限制,详细考察了同学们对类图、状态图、顺序图绘制的能力。但稍有遗憾的是,单元第二次作业的功能增加过于复杂,许多要求与第一次作业发生冲突,难以迭代开发,迫不得已只能选择重构。并且功能描述不清,题干中许多情况也因为情况复杂而难以考虑周全,UML 步 JML 后尘,成了模拟功能的牺牲品。

测试思维的演进

从第一次作业开始,直至第十三次作业,,中间的每一次作业都进行了测评机的构造,因为最后两次作业的数据限制较为复杂,保证不出现的情况较难通过设置规则在自动生成时规避,所以没有设计测评机。

最开始的测试使用 Python 语言编写,但是本身就没学过 py,所以效果不是很满意,于是后来选择迁移到 Java 上写测评。在设计测试程序的过程中不仅需要考虑到数据产生的合法性、是否符合数据限制、测试对于程序处理的覆盖性(分支、循环与边界),在写测试的过程中让我对自己的程序本身有了更完整的了解,能够明白坑点在哪里。但是由于测试程序基于我自己的思路来写的,所以可能不太容易找出自己的 bug,不过找别人的还是很灵(

总结课程收获

终于,oo 课程走到了尾声,这途中的十二次代码作业和四次博客作业对我而言都是十分珍贵的经历,在其中不仅初步掌握了 Java 语言的使用,还初窥了面向对象思想的门径。不同于大一时程设、DS这类面向过程编程的课程,oo 课利用多种场景教会了我面向对象、设计模式与其他的重要思想与技巧。虽然在课程的后半段出了点小问题,但课程的整体收获仍然十分充实。同时还告诉了我写程序时做测试的重要性。很遗憾因为时间问题我没有参选 oo 课程助教,但我也相信老师和新的助教们在新的一学年里能把 oo 课越办越好,办成干货满满的好课。