从代码到模型:OO 课程四个单元后的架构与测试反思

王予铎-24373074 2026-06-25 23:02:42

第四单元正向建模与开发实践总结

第四单元的三次作业与前三个单元最大的不同在于,它不再只要求我们根据需求完成代码实现,而是要求在开发过程中引入 UML 模型,通过类图、状态图和顺序图来表达系统设计。也就是说,本单元强调的是一种正向建模与开发的过程:先对问题领域进行抽象,识别系统中的核心对象、职责边界和交互关系,再基于模型完成代码实现,并在实现后反过来校准模型,使模型与代码保持一致。

在本单元的图书馆系统中,正向建模首先体现在对领域对象的拆分上。面对借书、还书、预约、取书、阅览、信用积分等业务,如果直接从输入输出入手编写代码,很容易把所有逻辑堆在一个中心类中,导致类职责混乱。通过一阶类图的设计,我需要在编码前思考哪些对象应当成为独立的类,例如 Library 作为系统调度者,User 表示用户状态和信用信息,BookTitle 和 BookCopy 区分书目与具体副本,Reservation  Loan 分别表示预约记录与借阅记录,而 Bookshelf、ReadingRoom、AppointmentOffice、BorrowAndReturnOffice 等类则对应图书馆中的不同部门。这一过程使系统结构在实现前就具有了较清晰的职责划分。

两阶类图在这个过程中起到了非常重要的作用。一阶类图更像是开发前的设计假设,它帮助我把需求中的名词、动作和状态初步映射为类、属性、方法和关联关系。它的价值不在于一次性设计出完全正确的结构,而在于迫使我提前思考系统的对象边界和协作方式。随着代码实现的推进,我会发现一阶类图中某些设计过于粗糙,例如有些职责原本集中在 Library 中,但在实际编码时更适合下放到具体部门类或领域对象中;有些信息原本只是临时变量,但后来发现它应当成为对象状态的一部分。二阶类图则承担了实现后的结构校准作用,它把最终代码中的类、属性、方法和关联关系重新沉淀为 UML 模型,使“设计意图”和“代码实现”之间形成闭环。

因此,我认为两阶类图的意义并不是简单地提交两份相似的图,而是体现了正向建模中的设计演进过程。一阶类图表达的是“我准备如何设计这个系统”,二阶类图表达的是“经过实现和修正后,这个系统最终如何组织”。二者之间的差异反映了需求理解、职责划分和实现细节不断被验证的过程。通过这种方式,UML 不再只是代码完成后的说明文档,而是参与了架构设计、实现反馈和结构复盘的全过程。

第四单元架构设计与 UML 模型追踪关系分析

在第四单元最终的架构设计中,我将图书馆系统划分为调度层、部门层和领域对象层。Library 是系统的核心调度类,负责接收并解析输入请求,根据请求类型协调不同部门完成业务操作。部门层包括 Bookshelf、TreasuredBookshelf、ReadingRoom、AppointmentOffice 和 BorrowAndReturnOffice 等类,它们分别负责普通书架、珍本书架、阅览室、预约处以及借还处相关的业务。领域对象层则包括 User、BookTitle、BookCopy、Loan、Reservation 等类,用来保存用户状态、书目信息、副本状态、借阅记录和预约记录。这样的分层使得系统不只是围绕输入输出展开,而是围绕业务对象及其协作关系展开。

从类图的角度看,最终代码设计与 UML 模型之间具有较清晰的追踪关系。类图中的主要类都能在代码中找到对应实现,类图中的属性大多对应代码中维护对象状态的数据成员,类图中的操作则对应业务处理中会被调用的方法。例如,User 类中的借阅限制、预约记录、信用积分等状态可以追踪到类图中的属性;AppointmentOffice 中的预约和取书行为可以追踪到顺序图中的消息;BookCopy 的位置变化则可以追踪到状态图中的状态迁移。通过这种对应关系,类图表达了系统的静态结构,代码则实现了这些结构背后的具体行为。

状态图主要刻画的是图书副本在系统中的流转过程。一本书在系统运行过程中可能处于书架、预约处、借还处、阅览室、用户手中等不同位置。代码中对图书位置的维护和转移,与状态图中的状态和迁移具有对应关系。例如,当用户借书成功时,图书副本会从书架流转到用户;当用户还书时,图书副本会进入借还处;当预约书被整理并送达预约处后,其状态又会发生变化。状态图使这些分散在代码中的状态变化被集中表达出来,有助于检查图书流转是否完整、是否存在不可达状态或不合理路径。

顺序图则用于表达特定业务场景中的对象交互关系。本单元中,预约和取书场景是顺序图关注的重点。顺序图中的 lifeline 对应代码中的类或对象,message 对应对象之间的方法调用或业务交互。例如,在成功预约新书的场景中,Library 会协调 AppointmentOffice 完成预约;在成功取书的场景中,预约处与用户之间会发生取书相关交互。顺序图将这些调用关系以时间顺序展示出来,使代码中分散的方法调用被组织成一条可理解的业务路径。

总体来看,第四单元的 UML 模型与代码之间不是完全独立的两套材料,而是同一个系统在不同层次上的表达。类图描述“系统由哪些对象组成以及它们之间有什么关系”,状态图描述“核心对象在运行过程中如何变化”,顺序图描述“对象之间如何协作完成某个场景”。最终代码则是这些设计的具体实现。通过对比 UML 模型与代码,我更加清楚地认识到,良好的架构设计不仅要让程序能够通过测试,还应当让系统结构能够被解释、被追踪、被维护。

大模型辅助正向建模的经验

使用大模型的重点不是直接“给我生成”,而是最大程度与它信息同步,引导它完成任务。

首要的重点在于给它完整的需求和官方包;其次,明确输出目标:类图、状态图、顺序图、代码结构分别要满足什么规则;要让大模型先明确要求,整理好各部分的职责,再开始生成具体代码,这里可以在生成前先与大模型同步一遍要求,确保它正确理解全部信息;另一个重点在于UML类图构建中,agent无法很好的像代码一样完成自动化测试,这里还是需要自己重点检查三个图的视觉效果与连接是否正确,避免出现“视觉上没有问题,实际代码层面没有正确构建”的情况。总的来说,大模型可以完成方案设计,代码生成与测试,但合理与否的决定权要始终握在自己手里。

架构设计思维的演进

回顾整个 OO 课程,我的架构设计思维经历了一个从“完成需求”到“组织系统”的变化过程。刚开始写第一单元时,我更多关注的是如何把输入转化为正确输出,架构设计意识还比较弱。面对表达式解析、化简和求导等任务,我最初容易从字符串处理的角度出发,试图通过局部规则解决问题。但随着需求逐步迭代,我逐渐意识到,如果没有稳定的对象结构,每一次新增因子、函数或嵌套规则都会使代码变得难以维护。因此,在第一单元中,我开始理解抽象语法树、递归下降解析、表达式对象等设计思想,认识到架构的作用不仅是让当前需求能跑通,更是为后续扩展保留空间。

第二单元的多线程电梯使我的架构设计思维进一步从“对象划分”扩展到“对象协作”。在这一单元中,仅仅把类拆开是不够的,还需要考虑线程之间如何通信、共享数据如何保护、调度策略如何与电梯行为解耦。相比第一单元中相对静态的表达式结构,第二单元的系统具有明显的动态性和并发性。我开始关注生产者消费者模式、请求队列、调度器、电梯线程之间的职责边界,也逐渐认识到架构设计需要处理的不只是类之间的关系,还包括运行时对象之间的协作方式。这个阶段让我意识到,好的架构应当让复杂的并发行为被封装在清晰的模块中,而不是让所有线程直接操作同一批状态。

第三单元的 JML 作业则让我开始从“实现逻辑”转向“规格约束”。在这一单元中,接口和方法不再只是代码组织形式,而是被精确定义了前置条件、后置条件和异常行为。我的架构设计思维也因此发生了变化:以前我更关心一个方法内部如何实现,现在则会先思考这个方法对外承诺了什么、调用者可以依赖什么、对象状态需要满足哪些不变量。JML 让我认识到,架构设计不仅包括类和模块的划分,还包括接口契约的设计。一个系统是否可靠,很大程度上取决于各个模块之间的边界是否清晰、行为是否可验证。

第四单元的 UML 建模则把我的架构设计思维进一步提升到模型层面。通过类图、状态图和顺序图,我开始在编码前思考系统结构,而不是写完代码后再回头解释代码。类图帮助我分析对象职责和静态关系,状态图帮助我整理核心对象的生命周期和状态迁移,顺序图帮助我观察特定场景下对象之间的交互路径。尤其是两阶类图的设计过程让我认识到,架构不是一次性完成的结果,而是在设计、实现和修正中不断演进的过程。一阶类图代表初始设计假设,二阶类图则代表实现后的结构校准,两者共同体现了从建模到开发再到复盘的闭环。

总体来看,我的架构设计思维从最初的“怎样把功能写出来”,逐渐转变为“怎样让系统结构清晰、职责稳定、行为可追踪”。第一单元让我理解了抽象和递归结构的重要性,第二单元让我理解了对象协作和并发边界,第三单元让我理解了接口契约和规格约束,第四单元让我理解了模型驱动和设计追踪。经过四个单元的训练,我更加认识到,架构设计并不是额外的形式工作,而是控制复杂度、支撑迭代和提升可维护性的核心手段。

测试思维的演进

在 OO 课程的四个单元中,我的测试思维也经历了明显变化。最开始,我对测试的理解主要停留在“用一些样例检查程序输出是否正确”。第一单元中,表达式处理任务的输入形式复杂,输出又存在等价表达的问题,因此仅靠手写样例很难覆盖所有情况。为了提高测试效果,我逐渐开始使用随机生成表达式、构造边界用例、与其他实现对拍等方式进行验证。这个阶段让我认识到,测试不能只依赖课程样例,而应当主动覆盖嵌套、符号、零项、合并同类项等容易出错的情况。

第二单元的多线程电梯作业使我对测试的理解从“结果正确”扩展到了“过程正确”。并发程序的问题往往不是每次都会稳定复现,例如死锁、饥饿、线程提前结束、请求丢失等问题,都可能只在特定时序下出现。因此,在这一单元中,我开始关注程序运行过程中的状态变化和时序行为,而不仅仅是最终输出。测试时不仅要看乘客是否最终到达目标楼层,还要检查电梯是否存在无意义运行、请求是否被遗漏、线程是否能够正常终止。这个阶段让我意识到,并发系统的测试需要更多地关注边界时序和异常调度情况。

第三单元的 JML 作业进一步改变了我的测试方式。由于 JML 给出了形式化规格,测试不再只是根据直觉构造输入,而是可以直接围绕规格中的前置条件、后置条件和异常条件展开。例如,对于图结构中的查询、连通性、最短路径、异常抛出等操作,我可以根据规格主动构造正常场景、边界场景和非法场景。这个阶段让我认识到,规格本身就是测试设计的重要依据。相比只根据实现写测试,根据规格写测试更容易发现实现与接口承诺不一致的问题,也能避免测试被自己的代码思路限制。

第四单元的测试对象又从代码行为扩展到了模型与代码的一致性。除了要保证程序输入输出正确,还需要检查 UML 类图、状态图和顺序图是否满足语义规则,是否与代码中的类、方法和对象交互关系一致。例如,类图中的类和方法需要能在代码中找到对应实现,状态图中的状态迁移需要与图书流转逻辑一致,顺序图中的消息路径需要能够表达预约和取书场景。这个阶段让我意识到,测试不仅可以验证代码,也可以验证设计模型;一个系统是否正确,不仅取决于运行结果,也取决于设计表达是否完整、可达、可解释。

从整个课程来看,我的测试思维经历了从样例测试到系统化测试的转变。第一单元让我开始重视随机测试和对拍,第二单元让我关注并发时序和运行过程,第三单元让我学会根据规格设计测试,第四单元让我认识到模型也需要被验证。测试的目标也从最初的“程序是否输出正确答案”,逐渐扩展为“系统行为是否符合预期、模块契约是否被满足、设计模型是否与实现一致”。这一变化使我更加理解测试在软件开发中的作用:它不仅是发现 bug 的手段,也是反过来推动架构改进和设计澄清的重要工具。

课程收获

我原本觉得,OO课程应该只会是一门教会我熟练使用JAVA的一些基本特性完成特定的任务的课程,但在学习中,我逐渐从架构与代码测试方面都越来越体会到“面向对象”的真意,并非拘泥于具体的代码形式,而是从逻辑与宏观的层面把握程序。尤其在大模型与相关的agent发展日新月异的今天,我们越来越可以摆脱代码实现层面的限制,而将精力放在更好的理解问题,选择架构适配问题的层面上。因而,这门课带给我的思维上的进步,正是我所真正需要的。

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

309

社区成员

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

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