2026 OO 课程总结

董宇皓-24373228 2026-06-19 08:43:13

2026 OO 课程总结

随着本周最后一次研讨课暨颁奖典礼落幕,这学期的面向对象课程终于画上了圆满的句号。回首这十六周的旅程:第一单元我们在文法解析中摸爬滚打,第二单元在与多线程作战,第三单元在 JML 契约下优化性能,而到了第四单元,我们体验了一把先画图纸,再盖大楼的正向建模开发流程。

本文将以第四单元的实践为主线,串联前三个单元的思考,全面总结架构设计与测试思维的演进。


一、 第四单元实践:正向建模与开发

在过去的编程习惯中,我往往是拿到指导书就开始“面向键盘编程”,一边写、一边想、一边重构,最后为了博客交差,再用 IDEA 插件逆向出一个 类图。然而,本单元引入的两阶类图机制影响了我的开发流程。

1. 一阶类图:勾勒骨架,厘清业务边界

在动手敲下第一行 Java 代码前,我先在 StarUML 中完成一阶类图(uml_pre.mdj):

  • 抽象出公共基类:我发现所有的书架、预约处、阅览室都具有“存放图书”的共性,于是我抽象出了基类 Location,统一维护 books 容器。
  • 确立调度核心:明确了 LibraryManager 作为全局控制器,包含 Map<String, User> userMap 和各类 Location,统筹 borrowreturnorder 等所有核心逻辑。
  • 局限性:从我的一阶类图可以看出

img

此时的方法设计还比较粗略(例如只有 +getAvailableBook() 的空括号,没有细化参数和返回值类型),此时的设计更多是头脑风暴的具象化。

2. 二阶类图:保持模型与代码的绝对同步

在具体的代码实现过程中,我发现一阶类图存在业务覆盖的盲区,于是进行了针对性的重构并在二阶类图(uml_ultimate.mdj)中同步更新

img

  • 引入 BorrowRecord 实体:在增加借阅期限和信用分系统后,简单的 Map<LibraryBookId, BookCopy> 已经无法满足需求。我重构加入了 BorrowRecord 类,用于精准封装 deadlinepenalized(是否已扣过分)状态,使得 User 类的职责更加内聚。
  • 像素级的细节对齐:为了满足评测机苛刻的 R1-R5 规则,我将二阶类图补全成了绝对标准的格式。例如,将一阶图中空泛的方法补全为 +getAvailableBook(isbn: LibraryBookIsbn): BookCopy,将静态方法 main 加上了下划线并补充了 : void 返回值。

二、 架构设计与 UML 模型追踪关系

在第四单元中,代码是严格顺应 UML 模型的投影。

1. 类图的精准投影

在我的代码中,UML 类图的连线几乎做到了 100% 的代码级追溯:

  • 继承关系:代码中 public class AppointmentOffice extends Location 严格对应类图中的泛化箭头。
  • 组合/聚合关系:UML 类图中 UserBorrowRecord 的实线关联,在代码中真实地体现为 private Map<LibraryBookId, BorrowRecord> borrowedCBooks

2. 状态图:以 Trigger 注解驱动状态流转

我的状态图

img

围绕着一本书(BookCopy)的生命周期展开。在代码侧,我利用 @Trigger 注解实现了模型与代码的咬合:

@Trigger(from = "bs", to = "user")
@Trigger(from = "tbs", to = "user")
private void handleBorrow(LibraryReqCmd cmd, User u) { ... }

公测逃课:为了满足评测机“任意简单路径必定有解(R3)”以及“同源外出 Guard 必须互斥”的要求,我在绘制状态图时让每个状态的出口绑定不同且独立的业务变量(如 bs 出发全用 credit 判定,tbs 全用 limit)。这在逻辑上 100% 避免了类似 limit==1 && limit==2 的路径死锁冲突。

3. 顺序图:严丝合缝的消息接力

顺序图

img

刻画了 EndpointUserLibraryManagerAppointmentOffice 的交互。
在绘制时,我深刻领悟了 R3 规则(跨类消息对应方法必须为 public)。我放弃了让 User 直接调用 LibraryManager.handleOrder(因为它是 private),而是通过调用其公共枢纽方法 dispatchCommand(),再由其分发至内部私有方法。这种符合封装特性的设计,让消息链的传递不仅合法,而且在面向对象原则上更加优雅。


三、 大模型辅助正向建模的体验与引导策略

在这一单元,我体验了大模型(Gemini)在架构设计中的辅助作用,可以用惊艳但不可盲信来形容。

1. 大模型的高光时刻

  • 繁杂数据的规范化处理:将 Java 源码转换到 StarUML 的画布上是一件极为枯燥的事。大模型可以瞬间将 LibraryManager 中二十几个方法的签名,精准翻译为符合 UML 规范的文本串(例如将 private void handleOrder(LibraryReqCmd cmd, User u) 翻译为 -handleOrder(cmd: LibraryReqCmd, u: User): void),极大地提升了建模效率。

2. 存在的盲区与“幻觉”

  • 忽视底层解析器机制:AI 有时为了“结构完整”,会在生成的 .mdj JSON 文件中加入 "ownedViews": [] 这种空视图数组,这会触发 StarUML 的 Bug 导致整个画布凭空消失。
  • 不理会特殊的评测规则:AI 在设计顺序图时,会自然而然地违背“私有方法不可跨类调用”的规则。

3. 如何科学引导大模型?

通过这些踩坑,我总结出一个 Prompt 策略:
绝不能只丢给它一句“帮我画个顺序图”,而是要把上下文约束作为 System Prompt 强行注入。例如:

“你现在是一个极其严格的 UML 架构师。请根据我的 Java 代码生成顺序图交互链。要求:1. 相邻两条消息的 Source 和 Target 必须首尾相接;2. 跨类调用的方法必须在代码中声明为 public;3. 请用 Endpoint 作为初始消息发送者……”
只有给出这样精确的边界条件,AI 才能成为真正好用的架构利器。


四、 架构设计思维的演进

回首四次大战,我的架构设计思维经历了四次涅槃:

  1. 第一单元(文法解析)
    刚接触递归下降时,我将解析和计算全部揉进一个 Calculate 类。经历重构后,我学会了提取 Monomial(单纯的数据载体)和 Poly(纯粹的行为载体),并利用工厂模式实例化各种 Factor,初窥了“高内聚低耦合”的门径。
  2. 第二单元(多线程电梯):从死锁到分层调度
    面对并发控制,我摒弃了让电梯“自己找活干”的混乱设计。抽象出了 GlobalContext 作为共享资源池,引入 Dispatcher 作为统筹大脑,而 Elevator 退化为只管按指令移动的机器。这种“策略与执行剥离”的架构,让双轿厢机制(HW7)的接入变成了轻而易举的事。
  3. 第三单元(JML 社交网络):从死磕规格到空间换时间
    JML 教会了我契约精神,但也让我明白:规格不等于实现。如果按照 JML 用两层 for 循环去找 mutualFollowingSum 必定 TLE。我开始在架构层面引入动态维护和缓存机制(如使用 LinkedHashMap 保证顺序,维护分桶结构优化 queryMostPopularVideo),让算法复杂度从 O(N^2) 降维到 O(1)。
  4. 第四单元(UML 图书馆):从“面向过程”到“模型驱动”
    本单元让我彻底告别了边写边改的野生开发模式。我在写代码前就已经明确了类之间的组合与关联、方法的前后置依赖。此时的架构设计,真正变成了一门清晰的工程学。

五、 测试思维的演进

随着业务复杂度的提升,我的测试手段也从原始的黑盒逐渐走向了体系化的沙箱测试:

  1. U1 随机测试:纯粹依赖 Python 生成海量随机多项式,与 SymPy 库对拍。这是一种被动碰运气的黑盒测试。
  2. U2 场景施压:为了捕捉多线程中的 Race Condition,我学会了构造特定高压场景。比如“1号车维修瞬间涌入 60 人”,或者“双轿厢 F2 换乘的 8 秒极限切换”。测试目的从“求对”变成了恶意“找茬”。
  3. U3 快照对比测试:JML 让我意识到,测试副作用(assignable)比测试返回值更重要。在 JUnit 中,我会在方法执行前后为对象拍“快照”,确保所有未被授权修改的容器大小和状态绝对没有发生越权污染。
  4. U4 边界检测:在本单元,我遭遇了边界条件错误。比如指导书规定“信用分 > 80 允许借阅”,起初我惯性地写成了 credit < 80 进行拦截(这意味着 80 分被放行了)。在后期的沙箱推演中,我专门挑出临界点(0, 40, 80)输入,成功在提交前猎杀了这个必挂强测的高危 Bug。
    同时,针对有同学说的“世界线偏移”问题(由于同日请求被 HashMap 的玄学顺序打乱导致分配副本号错乱),我在底层容器全部使用了 LinkedHashMap,从数据结构层面把测试的不确定性彻底摁死。

六、 课程收获与结语

历经十六周的魔鬼训练,OO 课程带给我的不止是 Java 代码的积累。

  • 工程化视角的重塑:我不再是一个仅仅关注“这道题怎么 AC”的代码工匠,而是蜕变成了一个会思考“如果需求增加,这套代码能抗住扩展吗?”、“锁的粒度是否会造成线程饥饿?”的软件开发工程师。
  • 严谨与契约精神:通过 JML 传声筒的研讨课与 UML 正向建模,我深刻认识到在现代多人协作软件工程中,一份清晰、无二义性的“契约文档”是何等重要。
  • 坚韧的抗压能力:经历了多线程排查debug的压力,经历了和评测机逐字校对类图参数的煎熬,我的逻辑严谨度进一步提升了。

一学期的面向对象之旅固然熬人,但在最后一次强测看到满屏绿色时,所有的疲惫都化作了无可替代的成就感。感谢 OO,让我踏进了面向对象设计的大门。

再见,2026 OO!杀青!

...全文
52 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

309

社区成员

发帖
与我相关
我的任务
社区描述
2026年北航面向对象设计与构造
java 高校
社区管理员
  • 孙琦航
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧