308
社区成员
发帖
与我相关
我的任务
分享随着第四单元最后一个版本的提交,OO(面向对象设计与构造)课程终于落下了帷幕。这门课不仅重塑了我的编程习惯,更在宏观层面改变了我对“软件工程”的认知。站在课程的终点,我想结合第四单元的图书馆模拟系统,以及贯穿四个单元的心路历程,为这趟旅程画上一个句号。
## 一、 正向建模与开发:两阶类图的作用解析
在过去的代码编写中,我们常常习惯于“边想边写,边写边改”的敏捷(野路子)开发模式。而在本单元,课程强制要求我们体验**正向建模**(Forward Engineering),即先画UML图,再写代码。
**两阶类图(一阶设计图与二阶终图)在这个过程中扮演了不可或缺的角色:**
1. **一阶类图(uml_pre)—— 蓝图与领域规约**
在敲下第一行代码前,一阶类图强迫我先去阅读厚厚的指导书,提取领域实体。在图书馆系统中,我提取出了 `Book`、`User`、`IsbnInfo`、`BorrowRecord` 和 `Reservation` 等核心实体。一阶类图就像建筑的施工图纸,它不关心具体是用 `ArrayList` 还是 `HashMap` 实现,而是确立了“用户可以持有借阅记录”、“图书隶属于某个ISBN大类”这样的宏观关联(Association)和基数关系。这极大地避免了后期代码结构的推倒重来。
2. **二阶类图(uml_ultimate)—— 演进与真实映射**
在实际编码中,我会发现有些一阶类图的构想过于理想化。例如,为了处理时间推移带来的复杂扣分逻辑,我必须在 `Library` 类中增加专门的时间追踪机制;为了迎合严苛的状态图评测,我需要在实体类中补充辅助变量(如 `targetState`)和专门的触发器方法(Trigger Methods)。二阶类图是对代码实现的精准复刻,它保证了设计文档与实际工程的同步,体现了架构随着细节的深入而不断演进的过程。
## 二、 架构设计与UML模型设计的追踪关系
本单元的图书馆模拟器具有极强的时间耦合性和状态流转性。我的核心架构设计如下:
* **中枢控制**:`Library` 类作为核心调度中心,管理 `sysDate`,并包含 `bookMap` 和 `userMap`。
* **信息隔离**:将书的公共属性抽离为 `IsbnInfo`,单本实体书为 `Book`,记录书本的 `LibraryBookState` 轨迹。
* **用户上下文**:`User` 类负责管理个人的 `BorrowRecord`、`ReadingBook` 以及 `Reservation` 状态。
**代码与UML的追踪关系分析:**
* **静态追踪(类图)**:代码中 `Map<LibraryBookId, Book>` 的聚合关系在类图上清晰地表现为 `Library` 到 `Book` 的 Association(1 对 多)。类图属性的方法签名与代码中的 `public` 方法达到100%映射。
* **动态追踪(状态图)**:`Book` 在书架、用户、借还处、预约处、阅览室之间的流转,构成了复杂的状态机。代码中 `updateState` 的逻辑分支,以及为过评测而专设的 `@Trigger(from="...", to="...")` 注解方法,与状态图中的 Transition 和 Guard 条件形成了严密的对应。
* **交互追踪(顺序图)**:从 `Main` 发起指令到 `Library` 调度,再到修改 `User` 状态,代码中的方法调用栈(Call Stack)与顺序图中的 Lifeline 和 Message 传递方向完全一致,真实还原了“预定新书 -> 取书”的生命周期。
## 三、 大模型(LLM)辅助正向建模与开发的实践总结
2026年的OO课程允许我们拥抱AI工具。在本次作业中,我深刻体会到了**“大模型不是万能的,但会用大模型是万能的”**。在复杂的业务场景下,直接让LLM“写一个图书馆系统”只会得到一堆无法运行的废代码。引导大模型的关键在于:
1. **分步投喂,确立边界(Contextual Prompting)**:不要一次性抛出所有规则。先让LLM理解实体关系(比如:“帮我设计实体类,不需要内部类”),再注入业务逻辑(比如:“加入信用分机制和预约过期机制”)。
2. **强制约束与打桩(Constraint Injection)**:针对UML评测机的死板规则,我明确引导LLM在代码中埋入“钩子”:比如显式声明 `targetState` 变量专门用于状态图的Guard条件,或者声明空方法专用于响应顺序图的 Message。
3. **闭环反馈机制(Error-Driven Development)**:当系统在复杂的时间推移逻辑(如 `doArrange` 的触发时机)上出现与样例不符,或由于对象空指针(如分配图书时未判空)导致报错时,需要将 **报错日志 + 具体的样例输入输出对比** 喂给LLM。大模型具备极强的逻辑修正能力,只要你给的定位足够精准,它就能迅速重构核心逻辑块。
## 四、 架构设计思维的演进
回首四个单元,我的架构思维经历了明显的升维:
* **第一单元(多项式解析)**:这是**“面向过程到面向对象”的阵痛期**。一开始只想用正则和长篇大论的 `if-else` 一波流解决,后来被迫学会了递归下降和表达式树,懂得了抽象出“因子”、“项”、“表达式”的层次结构,懂得了**封装与多态**。
* **第二单元(电梯调度)**:进入**并发编程领域**。架构设计的核心变成了“线程安全”与“解耦”。我学会了经典的“生产者-消费者”模型,明白了引入“调度器”类来分离请求分配与电梯运行的逻辑,深刻体会到了**高内聚低耦合**在多线程环境下的保命作用。
* **第三单元(社交网络/JML)**:体验了**契约式设计(Design by Contract)**。架构的重点在于如何在满足规格严苛的 `requires` 和 `ensures` 前提下,设计高效的数据结构(如并查集、最短路径缓存)来优化性能。我学会了将“做什么(规格)”与“怎么做(实现)”分离开来。
* **第四单元(图书馆/UML)**:这是**模型驱动架构(MDA)**的体现。从底层的代码实现,拔高到了顶层的系统建模。关注点变成了系统各组件的生命周期、状态机以及整体的拓扑关系。
## 五、 测试思维的演进
代码是写出来的,更是测出来的:
* **第一单元**:基本靠手工构造边界数据(如前导零、连续符号),测试思维偏向于**黑盒测试**和对拍。
* **第二单元**:手工测试完全失效(因为多线程的随机性)。我开始学习编写自动化评测机和定时投喂脚本。测试思维演进为**压力测试**和对死锁、线程饥饿的**并发场景测试**。
* **第三单元**:JUnit大显身手。测试思维转变为严谨的**单元测试**,根据JML规格划分等价类,针对前置条件和后置条件编写断言,体会到了测试驱动开发(TDD)的雏形。
* **第四单元**:由于状态复杂,测试重点转向了**场景驱动测试(Scenario-based Testing)**。我需要模拟用户的一整套行为流(借书-逾期-闭馆-整理-降分),测试思维更加关注**集成测试**和系统状态的一致性检验。
## 六、 课程收获总结
2026年的OO课程是一场身心俱疲但酣畅淋漓的修行。
在**硬技能**上,我熟练掌握了Java这门语言的各种特性,吃透了面向对象的核心理念,跨越了多线程编程的门槛,学会了阅读规格说明书,也掌握了UML建模的规范。
在**软实力**上,我顶住了每周迭代的巨大压力,学会了如何利用大模型作为“结对编程”的副手,更学会了如何在面对上百行报错时保持冷静,一步步Debug找到真相。
“纸上得来终觉浅,绝知此事要躬行。”感谢OO,让我真切地触碰到了“软件工程”的脉络,也让我在无数个熬夜写代码、画UML图的夜晚中,完成了从一名普通的“写代码的”到具有初步架构设计思维的“开发者”的蜕变。