一、总结本单元所实践的正向建模与开发,重点分析两阶类图在正向建模过程中的作用
第四单元和前三个单元最大的不同在于,它不再是直接写代码,而是要求我们先进行 UML 正向建模,再依据模型完成代码实现。整个流程大致变成了:
- 阅读指导书,理解图书馆业务规则;
- 抽象领域对象,绘制一阶类图;
- 根据类图完成代码;
- 在实现过程中补充状态图、顺序图;
- 最后通过二阶类图检查代码与模型之间的对应关系。
本单元的图书馆系统虽然算法难度不高,但业务状态较复杂。图书可能处于普通书架、精品书架、借还处、预约处、阅览室、用户持有等不同位置;用户可能进行借书、还书、预约、取书、阅读、归还、评分、续订等操作;第三次作业又增加了信用分、借阅期限和逾期判断。因此,如果直接写代码,很容易把大量逻辑堆在一个类中。
在一阶类图阶段,我主要完成了领域对象的划分:
Book表示 ISBN 层面的图书;BookCopy表示具体副本;User表示用户;Reservation表示预约记录;Location及其子类表示图书馆中的不同地点;LibraryManager负责全局业务调度。
两阶类图在正向建模中起到了“前后校验”的作用。
一阶类图负责提前约束设计
在编码前,一阶类图要求我先思考类的职责和关系。例如,如果没有区分
Book和BookCopy,后续的轨迹查询、借阅期限、预约指定副本都会很难实现;如果没有抽象Location,不同地点之间的图书移动逻辑也会产生大量重复代码。二阶类图负责实现后的反向校准
实现过程中,代码会自然地出现一些新属性和新方法。例如第三次作业中,我在
User中加入信用分和阅读日期,在BookCopy中加入应还日期和逾期惩罚标记,在Limit中统一封装权限判断。二阶类图的意义就在于检查这些实现细节是否仍然符合最初的架构方向。两阶类图形成设计闭环
一阶类图让我在写代码前建立系统骨架,二阶类图让我在写完代码后反思系统是否偏离原设计。这样 UML 就不只是提交材料,而是真正参与了“需求分析—架构设计—编码实现—反向检查”的全过程。
二、总结本单元作业的架构设计,并对比分析最终的代码设计和 UML 模型设计之间的追踪关系
本单元最终代码大致可以分为五层。
输入解析层
这一层主要包括
MainClass和CommandHandler。MainClass负责初始化图书馆、读取馆藏,并循环处理输入命令;CommandHandler负责把官方输入命令转换为内部方法调用,例如借书、预约、取书、阅读、还书、续订等。
这一层不直接处理复杂业务,只承担“命令分发”和“结果输出”的职责。
业务调度层
核心类是
LibraryManager。它维护全局的图书、用户、地点和预约队列,并负责主要业务流程,例如:borrowBook:借书;returnBook:还书;orderBook:预约;pickBook:取书;readBook:阅读;restoreBook:归还阅览室图书;renewBook:续订;open / close / arrange:开馆、闭馆和整理流程。
这个类相当于整个系统的调度中心,负责协调各个对象之间的状态变化。
领域对象层
这一层包括
Book、BookCopy、User和Reservation。Book保存 ISBN、类别、所有副本和评分;BookCopy保存副本编号、当前位置、持有者、移动轨迹、应还日期等;User保存持有图书、当前预约、阅读图书、信用分等;Reservation保存预约用户、预约图书、送达副本、失效日期等。
这种设计把不同层次的信息分开:ISBN 级别的信息属于
Book,副本流转信息属于BookCopy,用户状态属于User,预约生命周期属于Reservation。位置管理层
我用抽象类
Location表示地点,并派生出:BookshelfTreasuredBookshelfBorrowAndReturnOfficeAppointmentOfficeReadingRoom
各地点都维护自己持有的图书副本集合。这样图书移动时,只需要从旧地点删除、加入新地点,并调用
BookCopy.moveTo记录轨迹即可。规则辅助层
Limit用来封装借阅、预约、取书和阅读的规则。例如:- A 类书不可借阅和预约;
- B 类书同一时刻只能持有一本;
- C 类书同 ISBN 只能持有一本;
- 借阅和预约需要信用分大于 80;
- 阅读 A 类书需要信用分大于 40。
从 UML 到代码的追踪关系来看,整体是比较清晰的。
- 类名:一阶类图中的核心类在最终代码中基本都得到保留。
- 职责:
CommandHandler负责输入分发,LibraryManager负责业务调度,领域类负责维护自身状态。 - 状态:状态图中的书架、预约处、阅览室、借还处、用户持有等状态,对应代码中的
LocationType。 - 消息:顺序图中的对象交互,对应代码中从
CommandHandler到LibraryManager,再到User、Location、Reservation的调用链。
当然,最终代码和 UML 不可能完全一致。代码中会出现一些私有辅助方法,例如removeFromCurrentPlace、moveCopyTo、applyOverduePenalties等,它们更多是实现细节,不一定需要在一阶类图中过度展开。整体来看,本单元代码与 UML 模型之间基本达到了“核心结构一致、实现细节补充”的状态。
三、根据使用大模型辅助正向建模的体验,总结分析如何引导大模型在复杂场景中完成架构设计任务
在第四单元中,我使用大模型的重点从“辅助写代码”转向了“辅助建模”。这次体验让我意识到,大模型可以帮助整理需求和检查遗漏,但不能直接替代架构设计。
比较有效的使用方式如下。
先让大模型拆解需求,而不是直接生成类图
对于图书馆系统,可以先让它把需求分成几类:
- 实体对象;
- 用户操作;
- 图书状态;
- 整理流程;
- 信用分规则;
- 时间和过期规则。
这样可以避免一开始就得到一个看似复杂但不一定正确的类图。
要求它说明每个类的职责
比如不能只让它列出
Book、BookCopy、User,还要让它解释:- 为什么
Book和BookCopy要分开; - 为什么预约要抽象成
Reservation; - 为什么地点可以抽象成
Location; - 哪些逻辑应该放在
LibraryManager,哪些逻辑应该下放到对象自身。
- 为什么
控制输出粒度
大模型有时会过度设计,生成很多 Service、Factory、Strategy 类。对于 OO 作业来说,过多的类反而会增加复杂度。因此我会限制它:
- 不要设计过多无必要的类;
- 类图中的类要能在代码中真正落地;
- 方法和属性要能对应题目中的实际业务。
让它做反向审查
在完成一阶类图后,可以让大模型检查:
- 是否覆盖借书、还书、预约、取书;
- 是否覆盖阅读、归还、评分;
- 是否覆盖信用分、逾期、续订;
- 是否覆盖图书轨迹查询;
- 是否存在职责过重或状态归属不清的问题。
人工做最终决策
大模型生成的方案经常“看起来合理”,但不一定符合评测细节。比如日期计算、预约失效、闭馆整理、信用分上下界等规则,必须自己根据指导书推演。因此,大模型更适合当“需求整理器、方案生成器、遗漏检查器”,而不是最终设计者。
我的总结是:在复杂场景中使用大模型,关键不是问“帮我写一个架构”,而是分阶段引导它完成需求拆解、领域抽象、职责划分、模型审查。最终的架构取舍仍然由自己完成。
四、总结自己在四个单元中架构设计思维的演进
四个单元下来,我的架构设计思维经历了一个逐渐成熟的过程。
第一单元:从字符串处理到对象建模
第一单元是表达式解析与化简。最开始我关注的是怎么把表达式算对,后来逐渐把系统拆成词法分析、语法解析、表达式结构和多项式计算等部分。这个单元让我理解到,复杂问题不能一直用字符串硬处理,而应该抽象成对象和层次。
第二单元:从静态结构到动态协作
第二单元是电梯调度。这个单元让我意识到,架构不仅包括类之间的静态关系,还包括线程之间的动态交互。调度器、请求队列、电梯线程、共享资源之间需要正确协作,否则就会出现死锁、忙等或调度错误。
第三单元:从功能实现到规格约束
第三单元是 JML 规格化设计。这个单元让我认识到,代码不仅要能运行,还要满足清晰的契约。方法的前置条件、后置条件、副作用范围都需要被严格理解。架构设计也不只是“怎么写方便”,还要考虑对象状态是否满足规格。
第四单元:从代码驱动到模型驱动
第四单元要求先画 UML,再写代码。这让我真正体验到正向建模的意义。类图帮助我确定对象职责,状态图帮助我理解图书流转,顺序图帮助我梳理对象交互,二阶类图帮助我检查代码是否偏离设计。
总体来看,我的架构思维经历了:
- 第一单元:学会分层和抽象;
- 第二单元:学会并发协作;
- 第三单元:学会契约和状态一致性;
- 第四单元:学会正向建模和模型追踪。
从“能写出代码”到“能设计系统”,这是这门课对我影响最大的地方。
五、总结自己在四个单元中测试思维的演进
我的测试思维也随着四个单元逐渐变化。
第一单元:以输入输出正确性为核心
表达式单元中,测试主要围绕表达式等价性展开。我会构造括号嵌套、负号、指数、函数、选择因子、求导等样例,检查输出是否正确。这个阶段的测试更偏黑盒。
第二单元:开始关注并发时序
电梯单元中,很多 bug 不是每次都稳定出现。比如死锁、线程唤醒错误、请求分配错误,都和时序有关。因此我开始通过批量数据和特殊场景测试程序,例如大量请求、维修请求、换乘请求、双轿厢冲突等。
第三单元:按 JML 规格设计测试
JML 单元让我形成了更系统的测试方法。测试时不仅要看返回值,还要检查:
- 前置条件是否正确处理;
- 后置条件是否满足;
- 对象状态是否正确变化;
pure方法是否没有副作用;assignable限制之外的状态是否保持不变。
这让我从“测结果”转向“测契约”。
第四单元:按状态流转和模型设计测试
UML 单元中,测试重点变成了业务流程和状态转移。例如:
- 借书后图书是否从书架移动到用户;
- 还书后是否进入借还处;
- 整理后是否回到正确书架;
- 预约满足后是否进入预约处;
- 取书后是否由用户持有;
- 阅读后是否进入阅览室;
- 逾期、续订、信用分变化是否正确。
这一单元让我意识到,UML 图也可以成为测试依据。类图帮助检查对象职责,状态图帮助检查状态覆盖,顺序图帮助检查对象交互。
因此,我的测试思维大致经历了:
- 从测输出;
- 到测场景;
- 到测规格;
- 再到测模型和生命周期。
测试不再只是提交前的查错工具,而是帮助理解需求和验证架构的重要手段。
六、总结自己的课程收获
完成四个单元后,我最大的感受是:OO 课程很累,但确实让我从“写程序”逐渐转向“设计系统”。
知识层面的收获
四个单元分别训练了不同能力:
- 第一单元:表达式解析、递归下降、对象抽象;
- 第二单元:多线程、调度策略、线程安全;
- 第三单元:JML、规格化设计、JUnit 测试;
- 第四单元:UML、正向建模、状态图和顺序图。
编码层面的收获
以前写代码时,我更关注功能是否能跑通。现在我会更早考虑:
- 类的职责是否清晰;
- 数据应该归属于哪个对象;
- 状态变化是否集中管理;
- 未来迭代是否容易扩展;
- 是否存在过度耦合。
比如第四单元中,区分
Book和BookCopy、抽象Location、用Limit封装规则,都让后续新增功能更加自然。调试层面的收获
遇到 bug 时,我不再只是盲目输出调试,而会先判断问题类型:
- 是解析问题;
- 是状态更新问题;
- 是并发时序问题;
- 是规格理解问题;
- 还是架构职责划分问题。
这种分类思维让定位 bug 的效率提高了很多。
工具使用层面的收获
我也逐渐学会了更合理地使用大模型。它可以帮我整理需求、生成测试思路、检查遗漏和分析设计风险,但不能完全替代自己的判断。尤其是 OO 作业中很多细节和边界条件,必须自己认真推演。
工程思维层面的收获
这门课让我真正理解了抽象、封装、规格和模型的价值。好的架构不是为了让代码看起来复杂,而是为了让系统在需求变化时仍然可维护,在出现 bug 时能够快速定位,在多人协作时能够明确责任边界。
总的来说,四个单元构成了一条完整的训练路径:
- 表达式单元让我理解对象抽象;
- 电梯单元让我理解动态协作;
- JML 单元让我理解规格契约;
- UML 单元让我理解正向建模。
经过这门课,我对“面向对象设计与构造”有了更真实的理解:先理解需求,再抽象对象;先明确职责,再编写代码;先建立模型,再追踪实现;先设计测试,再相信程序。这是我在 OO 课程中最重要的收获。