2025_BUAA_OO_Unit4

Cdostan MVP++

OO第四单元的主题是UML建模语言,通过一个小型图书管理系统来引导我们从正向建模开始对整个程序进行设计。本单元难度较小,更多的是教会我们学会画UML图,学会看UML图,能够正确地从UML图中提取出关键元素,同时锻炼我们的正向建模思维。第四单元的结束也意味着整个OO课程结束了,回顾这学期OO的学习,我的感触也颇深。

第四单元

正向建模与开发

在第十三次作业的指导书中有这样一段话:

我对这段话的印象很深,深刻程度和下面这段话有得一比:

好了,回到正题。指导书明确“建议”我们先画UML图再敲代码,就是让我们对正向建模进行实践。本次我遵从指导书的意见,老老实实地先画了UML类图,然后再根据UML类图实现我的程序。
但完成作业后我仍然对“先画UML图“这一建议无感,难道不画UML图从头开始写代码就不叫正向化建模了吗?正向建模也不强制要求画UML图。在到后来的研讨课,当纪一鹏老师问到有多少人是直接敲代码的时候,在场三分之二的人举起了手,我不禁对这个开发模式有了更深的怀疑,所以先画UML图的意义何在?
思索之后,我对比了前三个单元的作业,化解了这个质疑。
首先我们没有正向建模来实现的单元就只有第三单元,第三单元的JML规格设计正好与正向建模相反,它强调在已知需求和结构的前提下,我们完善其内部细节实现,如果把程序设计分为头尾两部分,那JML规格设计就直接跳过了头这一部分,只管尾;而剩下的三个单元的作业我们都是从头开始,一直到把最后的尾部工作完成,也就是正向建模。
第一、二、四单元我们都是提取出核心概念与需求,从一个抽象的雏形逐步细化为具体的实现,比如第一单元中我们先明确有解析器和化简器,然后再细化实现,以及第二单元先明确有电梯、调度器等类,以及相应的线程,然后再完善内部的具体动作,第四单元也是如此,但是前两个单元可能并不会有人先去画UML图。
我在仔细回顾了这三个单元我的实现过程后,发现先画UML图让我的正向建模变得更加顺畅与规范。在一二单元我也会画图,但画的图不过是来提醒我相关的动作顺序,让我加深和加固对自己设计的理解而已,但UML图就不一样了。
正向建模中UML图优势:

  • 通过UML图,我能直观的理解自己设计的系统结构和行为,而不是经常写着写着就忘了自己这里为什么要这么设计或者自己设计这个部分有什么用
  • 设计好的UML图其实也展示了我的程序大体架构,因此在实现代码时有了一个大体框架,让我的代码不至于散成一团或者经常修改
  • UML图展示了我提前设计的每个类里面的属性与方法,这让我在实现代码时有了参照,而不是每次都新建一些空类然后不断切换类创建属性和方法
  • 在编写代码的时候如果我发现了什么问题可以在UML图中找到对应的部分以及与之关联的所有部分并进行修改,一方面避免了修改不完全的问题,另一方面在对UML修改的过程中也能通过其直观的形式发现可能新的设计问题

在第十三次作业,我根据我的UML类图很快就正确实现了整个程序,虽然本单元作业比较简单是一个原因,但我想UML图也起到了很大的作用。
但要让UML图正确起作用,一定需要认真谨慎地设计与绘图,不能潦草完事,那样和没有UML图就没什么区别了,好的UML图应该具有清晰、准确、简洁、一致、可扩展可维护等特点。

架构设计

UML类图

UML状态图

UML顺序图

功能说明

  • MainClass:程序入口,建立Library等类并获取输入让Library类处理
  • Library:图书馆类,抽象地实现相关操作方法
  • AoState:预约处,贮存此处的书籍,并提供方法供其他类访问以及修改
  • Bookshelf:书架,贮存此处的书籍,并提供方法供其它类访问以及修改
  • BroState:借还处,贮存此处的书籍,并提供方法供其它类访问以及修改
  • ReadingRoom:阅览室,贮存此处的书籍,并提供方法供其它类访问以及修改
  • Book:书,对官方包提供的类以及属性进行了封装,使其更方便使用
  • Manager:管理员,负责书籍的移动操作
  • User:用户,实现用户相关的动作

UML追踪

  • 类图:与JAVA类实现一一对应,类中若有其他类成员属性,则两个类存在关联关系。
  • 状态图:为Book类设置了几个状态,分别对应其当前所在的位置,内部方法作为Trigger实现状态转移。
  • 顺序图:跟踪用户预约书并取到所预约的书这一流程,通过各个相关类的方法作为消息来传递展现了整个流程的具体步骤,每个消息与其发送者或者接收者相关。

大模型体验

本单元的第一次作业我利用大模型来帮助我正向建模,主要是帮我梳理每个类中可能存在的方法与属性。但当时的大模型体验并不好,我只采纳了它一个建议,后来在实验课上学习到了如何一步一步设计prompt来引导大模型给出我们预期的结果,下来之后尝试重新利用大模型正向建模,比之前的效果好了很多。
总结下来,我认为应该以下面的步骤来引导大模型在复杂场景中完成架构设计任务:

  • 为大模型提供程序主要需求,可以是我们自己提炼的,也可以直接将需求文档发给它让他分析
  • 让大模型忽略细节,只从顶层设计的角度给出程序大体架构,并给出设计中的关联关系等
  • 分析其给出的架构,检查是否有设计问题并反馈给大模型让其修改
  • 让大模型根据顶层设计进一步完善更细节的内容

有一个好的引导是高效使用大模型的关键所在,有许多模式与框架,在第八次实验上也有所介绍:

第八次实验传送门
正确使用这些方法,我们就能一步一步让大模型给出一个我们满意的设计。

课程总结

设计思维演进

回顾整个OO历程,我发现我提升最多的并不是编写代码的能力,而是程序设计的能力。在第一单元之前,我可能是一个只会面向过程编程的毛头小子,甚至不能准确提取出类。
在第一单元,我第一次深刻体会到架构设计的重要性,当时递归下降的文法分析已经足够让我惊叹,我当时并没有重视架构设计,导致就算理解了递归下降,最后实现的代码也“高耦合,低内聚”,很多类设计出来根本没干事,或者是抢着干别的类该干的事。于是在第一单元的第二次作业中我对代码进行了重构,让架构逐渐好看了一点,但现在看来还是不尽人意。
第二单元堪称魔鬼单元,但这个魔鬼是针对线程安全上的,反而对于设计来说并没有那么难。或许是在第一单元已经有了些许经验,我第二单元的架构设计变得得心应手起来,从分析需求开始设计生产者-消费者模型以及程序应有的类,再通过画顺序图将电梯运行的逻辑展示清楚,最后也能实现“高内聚,低耦合”的设计思想。
第三单元相对来说轻松了很多,因为不需要我们自己设计程序架构了,只需要我们实现细节,这单元主要看重的是性能问题,我也时常打趣说“经过第三单元的无脑编程变得不会写代码了”。
再到第四单元,由于第三单元全是对着JML来实现代码,导致切换到第四单元的时候面对只有需求其他什么都没有的文档时变得有些不习惯,好在一步一步设计重新找回了正向建模的感觉,我觉得这一单元主要锻炼的就是我将UML应用在正向建模中的能力,进一步加强了我架构设计的合理性与准确性。我不知道我以后设计程序的时候会不会用UML,但我觉得一旦我用了UML,我的程序应该会优雅很多。

测试思维演进

本学期的OO课程很好地锻炼了我的测试能力,从第一单元到第四单元的测试过程也能看出我的测试能力的增强。
在第一单元我的测试方案是手编样例并对拍,但效果很差,因为每个人的程序运行相同的样例最后得到的结果可能都不同,因此对拍难度很大,我也并没有选择写评测机,当时觉得的主要难点是数据生成器仍然需要去根据文法来编写,同时sympy库也不能百分百判断准确。因此第一单元我的测试效率很低,三次强测中也都出现了bug,互测也被攻击得比较惨烈。
在第二单元,由于这一单元更加随机,且修复bug难度较高,因此为了提高自己程序的准确性,我决定编写评测机。评测机主要又数据生成器和checer组成,同时有一个负责评测的模块。本单元编写评测机的过程中,我认为最为困难的便是checker的编写,因为有程序有很多判错的情况,checker应该将正确覆盖到所有这些情况,同时还要保证判断的正确,因此程序和checker其实是互相检验的,在checker编写完后,需要通过已经实现的程序来检验checker正确性,待checker无误后再利用它来检验程序正确性。通过评测机,我完美通过了本单元的所有作业。
第三单元由于输出完全一定,所以可以直接使用对拍的方法来完成,同时本单元还要求我们编写Junit测试,这也让我学会了新的测试方法,进一步提高了测试质量。本单元的测试最主要在于数据生成器上,如何生成一个好的数据是关键,同时由于本单元看重性能问题,因此需要监测程序运行时间来查看是否有性能问题产生。
第四单元我仍然通过编写checker来检验程序正确性。虽然本单元作业难度远不如第二单元,但我觉得checker的编写比第二单元困难,因为本单元存在多个容器,同时交互程度也比第二单元更高,这相当于在重新实现一遍程序的同时加上检验模块了。
总的来说,经过OO的磨练,我的测试能力强了不少,以后我也会对程序进行高效的测试。

课程收获

经过一学期的OO磨练,我觉得我收获的东西其实就是上面写的这些东西,这些也是最为重要的东西。除此之外,我觉得我收获了编写大型项目的勇气,收获了正确使用大模型的方法,这也是对日后的学习生活十分有用的。
一些建议

  • 第四单元的所有UML图可以在本单元第一次作业的时候就引入,不然后面两次作业再画顺序图和状态图的时候由于程序架构和细节都已经确定,并不好画,甚至能够”逃课“式画法,完全无法体会到这两种图的作用。
  • 有关第三单元的性能部分或许应该放宽一点,因为很多点都涉及到动态维护等,虽然有的代码会被强测所构造的点卡,但能够构造另外的强数据使得其通过,但正常通过强测的代码不能通过,因此个人觉得第三单元的测试过度依赖数据构造方案,不同的实现对不同的方案性能是不同的,这点不好统一。
  • 互测合法性检验不通过时希望能够反馈相应问题,很多时候可能是平台的问题但没有通知,导致我们认为可能是自己数据生成器之类的出现错误,去无效地修复。
  • Title: 2025_BUAA_OO_Unit4
  • Author: Cdostan
  • Created at : 2025-06-10 10:05:00
  • Updated at : 2025-06-10 11:53:28
  • Link: https://cdostan.github.io/2025/06/10/OO/oo_Unit4/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments