308
社区成员
发帖
与我相关
我的任务
分享第四单元强制正向建模,要求先提交一阶类图再写代码,后期迭代后再提交二阶类图,一整套流程下来,深刻帮助我们理解了两阶类图的意义。
刚拿到图书馆需求时,规则极其繁杂:图书分 A/B/C 三类、借阅 / 预约 / 阅读三重权限、信用分增减扣分、开闭馆整理、预约过期、续订、逾期惩罚、阅览室当日回收…… 如果直接上手写代码,大概率会把所有数据、逻辑全塞在一个 Library 类里,后期新增续订、评分功能时根本无从下手。
一阶类图就是我梳理需求的草稿纸:
Library、各类场地(普通书架、精品书架、借还处、预约处、阅览室)、核心实体(用户 User、单本图书副本 BookCopy、预约单 Reservation),提前划分每个类的职责,杜绝 “万能大类”;画完一阶图再写代码,最大的好处是提前规避架构硬伤。比如建模阶段我就意识到借阅限制、信用校验逻辑应该封装在 User 类,而不是在 Library 的借书分支里写一堆 if,后续新增阅读、预约权限时,只需要扩充 User 的校验方法,不用大面积修改业务代码。
但一阶类图存在天然短板:只覆盖基础业务框架,三次作业迭代新增的细节(逾期惩罚标记、预约过期时间计算、续订延期逻辑、ISBN 评分存储)无法提前预判,代码实现后会多出很多属性与方法,模型和代码出现偏差,这就是二阶类图存在的必要性。
完成全部编码、三次功能迭代后,我对照完整代码绘制二阶类图,修正一阶图缺失的属性、方法,补充所有关联关系,满足评测 R1-R5 一致性校验标准,它的作用主要有三点:
User私有成员creditScore、方法canReadToday(),在 Java 代码中可以精准找到对应实现;Library 聚合所有场地类的聚合关系,代码中也通过成员变量一一体现。不管是自己复盘代码,还是助教检查程序,都能通过类图快速定位对应代码位置。@Trigger注解的状态转移方法,都能在二阶类图中找到;顺序图中所有生命线(Library、User、AppointmentOffice 等),全部来自类图定义的类,不会出现无中生有的对象与方法。以前总觉得画图是负担,做完图书馆作业才理清两者分工:
结合需求复杂度,我把系统划分为三层,所有分层、类间关系都完整复刻在 UML 二阶类图中:
(1)静态结构一一对应
private boolean overduePenalized标记逾期是否扣分,在二阶类图中完整标注;(2)关联 / 聚合关系双向匹配
UML 中 Library 聚合所有场地、User 聚合多个 BookCopy、AppointmentOffice 关联 BookCopy 与 Reservation,这些关联全部通过代码中的成员集合实现。比如private final Map<BookCopy, Reservation> reservedBooks,对应预约处与预约单的关联关系。
(3)行为模型与代码注解联动
状态图中所有状态转移 Trigger,对应代码中@Trigger注解标记的方法;顺序图中预约、取书的对象交互消息,对应 Library、User、AppointmentOffice 之间互相调用的方法,实现静态模型、动态行为、业务代码三者打通。
这次写图书馆架构、画类图前期,我全程借助大模型辅助梳理需求、搭建初始架构,踩了不少坑,也总结出一套适合复杂业务系统的建模引导方法:
简单来说,大模型只能做辅助梳理工具,不能替代自己对业务规则的理解,必须自己把控架构边界、业务约束,再借助 AI 简化重复建模工作。
回顾四个单元,我的架构思维变化如下:
拿到需求直接写主类,纠结很久不知道应该设计什么类负责什么东西。后来架构写的太过于混乱参考大模型重构,修改一个功能就需要大规模改代码。
引入多线程后,学会了生产者-消费者模型和流水线模式。架构思维从普通的静态架构演进到了“动态的线程安全交互”,学会了利用调度器来解耦请求和执行。
了解到JML 定义每个方法、每个类必须遵守的行为契约,可约束一套可证明、无歧义的可靠架构。这一单元让我认识到接口与规格的威力。架构不再只是类的堆砌,而是基于前置条件、后置条件和不变式的严格契约。
严格遵循需求拆解→一阶类图预设计→编码实现→迭代更新二阶类图→行为建模完整流程。熟练运用分层、单一职责、高内聚低耦合思想,通过建模提前规避架构缺陷,代码可拓展性极强,新增续订、评分、逾期惩罚等功能时,仅需要扩充对应类的方法,无需重构整体结构。
由于第一单元完全是静态的。写完代码运行样例,输出和样例一致就认为程序正确。测试思维停留在黑盒层面,主要依靠构造极端的、复杂的嵌套表达式。
主动手动构造各类临界输入单独运行验证,覆盖大量容易出错的边界场景:
采用 “先单线程、再多线程” 的分层测试流程,分步验证功能,降低并发问题的排查难度:
本单元同时接触两套正确性保障工具:JML 行为规格与 JUnit 自动化单元测试,我开始建立 “先定规范、再写代码、最后自动化校验” 的基础思路,但二者结合运用的完整思维尚未成型。
编码阶段我会为核心实体、业务方法补充 JML 规格,借助@requires/@ensures明确方法输入输出约束;同时使用 JUnit 编写自动化用例,主动覆盖各类极端边界:数据数量上限、空集合输入、临界日期、参数极值等容易出错的单点场景,不再只依赖样例手动调试,大幅减少随手调试带来的漏测问题。
图书馆作业是交互式评测,评测机会根据我的输出动态生成还书、续订、取书指令,倒逼我建立完整测试思维:
测试思维演进:仅依赖样例 → 零散边界测试 → 分模块 + 全链路场景系统化测试。
从前写代码只追求 “功能跑通”,现在明白可维护、可拓展、规范的架构远比快速实现功能重要。面向对象不是单纯使用类和对象,而是用封装、继承、关联、聚合抽象现实业务,用模型提前规划系统,从根源降低代码复杂度。正向建模思维不仅适用于课程作业,后续小型项目开发都可以复用这套流程。
完整掌握需求拆解→UML 正向建模(两阶类图、状态图、顺序图)→编码实现→迭代重构→一致性校验的软件工程流程,学会通过 UML 图沉淀系统文档,看懂静态结构与动态行为的区别,理解模型与代码双向追踪的意义。
熟练运用单一职责、高内聚低耦合设计原则,懂得拆分调度层、容器层、实体层,避免巨型类;学会合理封装权限校验、数据操作逻辑,减少重复代码;理解状态管理思想,而非零散记录状态变量。
不再依靠随机调试找 bug,能够按业务场景、边界条件设计完整测试用例,针对交互式评测场景模拟联动操作,快速定位逻辑错误。
清楚大模型的优势与局限,掌握分步引导 AI 完成需求梳理、架构草稿、伪代码编写的方法,同时保持自主设计主导权,不依赖 AI 生成完整代码,规避架构设计缺陷。
四个单元一路走来,踩过无数坑:巨型耦合类、模型代码两张皮、边界逻辑 bug、画图应付评测…… 但第四单元图书馆正向建模的完整实践,让我真正读懂了面向对象设计的核心。这门课教会我的不只是 Java 语法、UML 画图,更是一套解决复杂业务系统的工程化思维。今后再遇到复杂业务开发,我会先静下心梳理需求、搭建模型,再动手写代码,这是 OO 课程留给我最有价值的收获。