OO Unit4 博客总结 && 课程总结

沈钡-24373462 2026-06-20 01:52:57

面向对象设计与构造——第四单元及课程技术总结

引言

本技术博客围绕2026年面向对象设计与构造课程的第四单元(图书馆管理系统)三次作业及全课程内容,进行全面的回顾与总结。在第四单元中,我们首次实践了正向建模与开发,通过两阶UML类图指导系统架构设计,并辅以状态图和顺序图描述对象行为与对象间交互;同时,大语言模型在辅助设计、代码生成与错误排查中发挥了重要作用。以下将从六个维度展开:正向建模实践、架构设计与追踪关系、大模型辅助设计体验、架构思维演进、测试思维演进以及课程总体收获。


一、正向建模与开发实践:两阶类图的核心作用

第四单元的核心训练目标是正向建模——即在编写代码之前,先通过UML类图完成架构设计,再依据设计进行实现。这与前三个单元“先写代码后画图”的逆向工程形成鲜明对比。

在第十四次、第十五次作业中,我们实践了两阶类图的正向建模流程。

1.1 一阶类图:架构的蓝图与契约

一阶类图在代码编写前完成,其核心作用体现在三个方面:

(1)确立核心抽象与职责边界

绘制一阶类图时,必须首先识别系统中的核心实体及其关系。以图书馆管理系统为例,我们需要抽象出 LibraryManager(管理核心)、BookBookCopy(图书与副本)、User(用户)、各种地点类(BookshelfAppointmentOfficeBorrowReturnOfficeReadingRoom)等。这个过程迫使我们思考每个类应当承担的职责——例如,借阅限制逻辑应该放在 User 还是 LibraryManager 中?图书移动轨迹是 BookCopy 的属性还是独立管理?

(2)强制分离关注点

一阶类图不允许我们一开始就陷入实现细节。例如,我们在一阶图中只定义了 LibraryManager 具有 borrowBookreturnBook 等方法,但不关心内部如何实现。这种抽象层次的强制提升,帮助我们建立了更清晰的模块边界。

(3)预判迭代需求

在第十五次作业中,新增了信用分系统、借阅期限和续订功能。由于一阶类图已经建立了良好的基础架构,我们只需在一阶图基础上增加 CreditManager 类和 BorrowRecord 类,并在相关类中补充 credit 属性和 renew 方法即可,而不需要对整体架构推倒重来。

1.2 二阶类图:从设计到实现的桥梁

二阶类图在代码完成后进行修正,其核心作用包括:

(1)详细化设计契约

一阶类图中,方法往往只有名称而无参数和返回值。二阶类图要求我们补充完整的参数列表和返回类型——例如 borrowBook 的参数从无到有,变为 (String studentId, ISBN isbn, LocalDate date): BookCopy。这使得类图从“示意”升级为“精确契约”,可以直接指导编码和测试。

(2)检验设计与实现的一致性

评测系统对二阶类图执行R1-R5的全面检查,包括属性名、方法名、可见性、返回值类型的匹配。这一过程揭示了许多设计偏差——例如我们在类图中遗漏了 Main 类的某些辅助方法,或者方法参数顺序与代码不一致。修正这些偏差的过程,本质上是在验证我们的实现是否忠实于原始设计。

(3)管理架构演化

从一阶到二阶,类图的变化(如类名从 Library 改为 LibraryManager、新增 CreditManagerBorrowRecord)被记录在重构说明中。这种演化追踪帮助我们理解设计决策的变更原因,也为后续维护提供了历史依据。

关键体会:两阶类图的设计并非“先画图再写代码”那么简单,而是一个螺旋上升的过程——设计指导实现,实现反馈修正设计,最终两者趋于一致。评测系统的相似度检查(要求两阶类图相似度不低于60%)正是为了确保我们没有在一阶时“敷衍画图”而在二阶时“彻底重来”。


二、架构设计与追踪关系分析

2.1 整体架构设计

本单元作业采用了分层架构 + 领域模型的设计思路:

核心管理层LibraryManager 作为门面,负责协调所有操作(开馆、闭馆、借阅、归还、预约、取书、阅读、评分、续订、信用查询),持有所有地点对象和用户、图书的集合。

领域模型层

  • 图书域ISBN(身份标识)、Book(同ISBN的聚合根,管理副本集合)、BookCopy(单个副本,记录状态和移动轨迹)
  • 用户域User(管理借阅记录、预约记录、信用分、阅读状态)、BorrowRecord(单次借阅的期限和续订)、OrderRecord(单次预约的过期状态)
  • 信用域CreditManager(集中管理所有用户的信用分,支持查询和调整)

地点管理层BookshelfTreasuredBookshelfAppointmentOfficeBorrowReturnOfficeReadingRoom,各自管理所在位置的图书集合,提供添加、移除、查询功能。

辅助层Arranger(整理策略)、BorrowLimit(借阅限制检查)、Grader(评分计算)、MoveInfoMoveTrace(数据传输对象)。

2.2 UML模型与代码的追踪关系

正向建模的核心价值在于保持设计模型与实现代码的可追踪性。以下是几个关键的追踪关系实例:

追踪维度UML模型Java代码一致性检查
类名LibraryManagerpublic class LibraryManager名称完全匹配
属性bookshelf: Bookshelfprivate Bookshelf bookshelf;名称、类型、可见性一致
方法borrowBook(studentId, isbn, date): BookCopypublic BookCopy borrowBook(String, ISBN, LocalDate)参数顺序、返回值类型一致
关联关系LibraryManager 持有 AppointmentOfficeprivate AppointmentOffice appointmentOffice;属性类型体现关联
枚举Location { BOOKSHELF, ... }public enum Location { BOOKSHELF, ... }枚举项一一对应
状态图Trigger@Trigger(from="bs", to="user")@Trigger(from="bs", to="user") public void borrow()状态名称和方法名匹配
顺序图消息orderNewBook: User → LibraryManager@SendMessage(from="User", to="LibraryManager") public void orderNewBook()消息名和方法名一致

追踪关系的实践意义

  1. 变更影响分析:当需要修改一个类的方法签名时,可以通过追踪关系快速定位到类图中需要同步更新的部分,以及代码中所有调用该方法的地方。

  2. 逆向验证:评测系统的R2-R5检查实际上是在验证“我们最终写的代码是否还是当初设计的样子”。如果偏离过大,说明要么设计不合理,要么实现时丢失了架构约束。

  3. 知识传递:类图作为文档,可以帮助其他开发者快速理解系统架构,而不需要通读所有代码。


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

在本次作业中,我大量使用了大语言模型来辅助完成架构设计和代码实现。以下是基于这一体验总结的有效引导策略:

3.1 明确约束与规范

大模型在开放场景中容易产生幻觉,因此必须在一开始就明确所有硬性约束

  • 评测规则:R1-R5的检查项、关键词覆盖率要求、相似度检查标准。我会直接将指导书中的评测标准粘贴给模型,让它理解“什么是对的”。
  • 文件格式.mdj 文件的正确结构(ownedElements而非childrenModelname字段必须为"Model"represents必须使用"class.XXX"格式等)。这些细节曾多次导致解析失败,但一旦明确告知,模型就能稳定输出。
  • 代码规范:单方法不超过60行、使用官方包的具体类名和方法签名。

3.2 分阶段推进,逐步细化

正向建模本身就是一个逐步细化的过程,这与大模型的能力边界高度契合:

  • 第一阶段(一阶类图):只需提供类名、属性名、方法名(无参数细节),重点是覆盖关键词和核心实体。模型在这一阶段可以快速生成架构草图。
  • 第二阶段(二阶类图+代码):逐步补充方法参数、返回值类型、可见性,并确保类图与代码的一致性。我会将评测机的错误信息直接反馈给模型,让它针对性修正。

3.3 提供反馈迭代修正

大模型最强的能力之一是基于反馈快速修正。在调试顺序图消息路径时,评测机反复提示“起始消息不存在”,我将错误信息直接提供给模型,模型能够分析出问题在于represents格式、predecessor/successor字段的写法等,并逐次调整直到通过。

有效的反馈方式

  • 粘贴完整的评测输出(而非仅描述“出错了”)
  • 提供期望输出与实际输出的对比(如stdout vs myout)
  • 明确指出哪一部分需要修改(如“顺序图片段”)

3.4 人保持架构决策权,模型负责细化与检查

大模型适合完成机械性、规则明确的任务——例如按照规则生成类图的JSON结构、检查方法签名是否匹配、生成符合规范的@Trigger注解。但核心的抽象设计决策——例如将信用管理独立为CreditManager还是放在User中、借阅限制应该由哪个类负责——仍应由人类完成。

在实践中,我会先自己画出架构草图(哪些类、什么关系),然后让模型帮我补充细节、检查一致性、生成规范文件。这种人机协作模式既发挥了人类的抽象思维能力,又利用了大模型对规则和细节的精确处理能力。

3.5 引导大模型完成复杂架构设计的总结

  1. 提供完整上下文:指导书、官方包API、评测规则缺一不可。
  2. 设定明确边界:告知模型哪些可以自由发挥(如整理策略),哪些必须严格遵守(如输出格式)。
  3. 迭代式推进:先粗后细,每步验证,及时反馈。
  4. 利用模型的记忆能力:在同一对话中持续修正,模型能够记住之前的错误并避免重犯。
  5. 保留人工决策:架构的核心抽象应由人完成,模型是高效的执行者和检查者。

四、四个单元中架构设计思维的演进

回顾整个2026OO课程,我的架构设计思维经历了从“能跑就行”到“设计先行”的显著转变。

4.1 第一单元:表达式解析——面向过程的遗留

第一单元的核心任务是表达式解析与化简。当时的我虽然使用了多个类(MainSolverExprPolynomialTerm),但本质上仍然是面向过程的思维——数据在类之间流转,类是“函数包”而非真正的对象。Expr类的解析方法长达数百行,圈复杂度爆表,体现了典型的“上帝类”问题。

核心问题:我关注的是“怎么解析字符串”,而不是“如何用对象协作表达语义”。PolynomialTerm虽然封装了数据,但行为逻辑全在Expr中,缺乏真正的职责分配。

4.2 第二单元:多线程电梯——层次化架构的觉醒

第二单元的电梯调度系统迫使我思考层次化设计。我采用了四层架构(输入层→调度层→电梯井层→电梯层),每一层有明确的职责边界。这是第一次真正体会到“高内聚、低耦合”的好处:第六次加检修、第七次加双轿厢,只需修改对应层,整体架构不受影响。

关键收获:我开始理解“线程安全不是加锁越多越好”,而是“控制共享资源的访问顺序”。这为后续理解“不变式”和“契约”埋下了伏笔。

4.3 第三单元:JML规格化——契约驱动设计的启蒙

第三单元的JML让我第一次接触到形式化规格。我学会了阅读前置条件、后置条件、不变式,理解了“设计契约”比“实现功能”更重要。在迭代开发中,我发现严格遵循JML的实现往往更简洁、更少bug——因为契约已经帮我排除了大量边界情况。

关键转变:从“写代码再测试”到“先理解契约再编码”。这为第四单元的正向建模奠定了思维基础。

4.4 第四单元:图书馆管理系统——正向建模的完整实践

第四单元是前三单元的集大成者:我需要先画UML类图(正向建模),再编写代码,最后通过状态图和顺序图验证设计。两阶类图的实践让我体会到:

  • 一阶类图就像建筑的蓝图,定义核心抽象和关系。
  • 二阶类图像施工图,精确到每个方法的参数和返回值。
  • 评测系统的R1-R5检查像监理验收,确保实现不偏离设计。

最重要的架构思维跃迁:我认识到好的架构不是“写出来的”,而是“设计出来的”。在第十五次作业新增信用分系统时,我能够在一阶类图基础上平滑扩展,而不是像第一单元那样在单个类里堆砌代码。这正是一学期训练的核心成果。


五、四个单元中测试思维的演进

5.1 第一单元:手工构造边界用例

测试方式非常简单粗暴:手工写几个表达式,对比输出。没有自动化测试框架,没有系统的边界覆盖,完全依赖评测机的“公测”和“互测”。Bug发现效率低下,很多隐藏问题直到互测才暴露。

核心缺陷:将“通过评测”等同于“程序正确”。

5.2 第二单元:日志驱动的并发测试

多线程的调试难度远高于单线程,我学会了用日志定位问题:在关键位置输出时间戳和线程状态,还原并发执行顺序。此外,开始有意识地构造压力测试(大量并发请求)和边界测试(极端等待时间、瞬时请求)。

关键提升:认识到并发程序的正确性不能靠“跑一遍看看”,必须通过多次重复测试和日志分析验证。

5.3 第三单元:基于规格的JUnit测试

这是测试思维的重大转折点。我学会了依据JML规格构造测试用例

  • 前置条件覆盖:构造满足和不满足requires的用例,验证异常行为。
  • 后置条件验证:使用assertEquals严格检查返回值、状态变化。
  • assignable检查:确认非指定对象未被修改。

我还掌握了边界测试的系统化方法:空集合、极值、重复操作、重叠匹配等。

核心理念转变:测试不是为了“证明程序对”,而是为了“发现程序错”。好的测试用例来源于对规格的深入理解,而非随机构造。

5.4 第四单元:交互式评测下的系统验证

第四单元的评测是交互式的:评测机根据程序的输出动态生成后续输入(如还书、取书、续订指令)。这意味着我的程序不仅要正确响应给定输入,还必须保证输出的副本号、移动轨迹等与后续输入一致。

这一阶段我学会了端到端集成测试

  • 不再孤立测试单个方法,而是运行完整场景。
  • 对比实际输出与期望输出,定位逻辑错误。
  • 利用评测机的反馈信息逐步修正边界逻辑(如逾期扣分的时机、精品书架调整的时机)。

最终形态的测试思维:测试覆盖全流程,关注对象状态的完整生命周期,确保系统在长时间运行中保持一致性。


六、课程收获

6.1 架构设计能力的质变

从第一单元的“上帝类”到第四单元的“两阶类图正向建模”,我完整经历了一次架构设计思维的升级。现在我能自然地问自己:

  • 这个类的职责是否单一?
  • 两个类之间的耦合是否可以通过接口或中间层降低?
  • 如果需求变化,哪些类需要修改,哪些可以保持稳定?

这些思考已经成为编码前的“肌肉记忆”。

6.2 多线程与并发安全的实践能力

第二单元让我掌握了synchronizedwait/notifyReentrantLock等核心同步机制,理解了死锁、轮询、可见性等并发陷阱。虽然不是所有人都会经常写多线程代码,但这种对“共享资源有序访问”的理解,对理解分布式系统、数据库事务等高级主题有奠基作用。

6.3 形式化规格与契约编程的启蒙

第三单元的JML让我认识到:代码之前,先写契约。前置条件和后置条件不仅是文档,更是可执行的需求。这种思维方式让我在第四单元面对复杂业务规则时(如借阅期限、信用分加减分规则),能够更系统地梳理逻辑,而不是边写边改。

6.4 正向建模与设计追踪的方法论

第四单元的两阶类图实践,教会了我“先设计再实现”的完整流程。更重要的是,通过R1-R5的检查,我体验了设计模型与代码实现之间的追踪关系——这在工业界是架构评审和代码审查的核心技能。

6.5 大模型辅助开发的实用经验

整个课程中,我深度使用大模型完成了大量工作:生成UML类图JSON、检查方法签名一致性、定位逻辑错误、撰写博客文档。我体会到:

  • 大模型是“加速器”而非“替代品”:核心设计决策必须由人完成,但机械性、规则明确的任务可以交给模型。
  • 反馈迭代是高效协作的关键:将评测错误信息直接反馈给模型,能快速修正问题。
  • 约束前置是避免幻觉的手段:在对话开始时提供完整的指导书、API文档和评测规则,模型的表现会显著提升。

6.6 对软件工程的整体理解

这门课程让我从“写作业的学生”视角切换到“构建系统的工程师”视角。我理解了:

  • 代码是暂时的,设计思维是永恒的:语言、框架会过时,但抽象能力、模块化思维、契约意识永远不会。
  • 质量不是测出来的,是设计出来的:好的架构天然易于测试、易于扩展、易于维护。
  • 工具是思维的延伸:无论是UML建模工具、JUnit测试框架,还是大语言模型,善用工具能大幅提升开发效率和代码质量。

最后:感谢课程组精心设计的四次迭代作业,让我在短短一个学期内,从面向过程的“代码工人”成长为具备架构思维和正向建模能力的“软件工程师”。这门课不仅教会了我Java和UML,更教会了我如何思考、如何设计、如何协作。这些收获将伴随我未来的整个开发生涯。

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

308

社区成员

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

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