2026面向对象第三次博客作业

颜灿-ZC061016 2026-05-28 20:59:29

一、 对 JML 和规格驱动开发的理解

JML是一种面向 Java 的行为接口规格语言,其核心价值在于通过契约编程,在代码实现前建立严密、无歧义的数学化行为契约。

  • 行为契约的明确化:JML 通过 requires 明确方法调用的前置条件,通过 assignable 约束副作用的范围 ,再通过 ensures 保证方法执行完毕后的后置状态,从而在方法调用者与具体实现者之间建立了一套标准的信任机制。
  • “做什么”与“怎么做”的解耦:规格驱动开发的核心在于深刻体会规格是对行为结果的约束,而非对实现过程的指导。JML 规格为了保持数学上的严谨性,经常使用 \forall\exists 等量词或者多重嵌套循环来描述最终的状态集 。如果实现者只是机械地将规格直译为代码中的多层 for 循环,将导致严重的性能灾难。
  • 规格约束下的实现自由:在开发过程中,真正的规格驱动要求我们在完全满足 ensures 和异常处理的前提下,自由地对底层数据结构和算法进行重构优化。例如,规格中频繁出现利用数组遍历来寻找特定 ID 的元素,而我们在实现时可以将其优化为 HashMap,在保证行为等价的同时,将空间和时间复杂度提升至最优。

二、 总结 JUnit 测试的经验

在测试中,针对复杂的方法编写 JUnit 单元测试,是保障系统正确性与稳定性的核心手段 。一份高质量的 JUnit 测试应具备以下层次的设计:

1. 全面覆盖异常边界与抛出优先级

  • 针对前置条件不满足导致的异常路径,需构造完备的测试数据以激活所有 signals 分支 ,例如分别构造针对用户 ID 不存在、排名参数非法、系统无视频、以及冷启动等各种异常场景 。
  • 在多个异常条件同时成立的复合场景下,必须专门编写异常优先级校验用例(例如:同时触发用户不存在与非法排名时,验证是否先抛出 UserIdNotFoundException),确保代码分支的拦截顺序与规格严格一致。

2. 精准验证后置条件的正确性

  • 候选集过滤验证:需要构造复杂的拓扑网络,确保智能推荐的候选集能够精准剔除用户自身以及已经关注的用户 ,并正确处理诸如反向关注、三角关注等边缘关系。
  • 排序与决胜(Tie-Break)规则验证:针对根据分区兴趣度与 UP 主影响力计算出的综合得分进行降序排列测试 。特别需要构造“多名 UP 主得分完全相同”的极端等价类,深度验证在同分情况下是否严格按照用户 ID 的升序(字典序)进行截断与输出。

3. Pure 方法与状态不变量的绝对防御

  • 对于标注为 pure 的方法,其后置条件约束为状态不变量(即副作用为 \nothing) 。
  • 在测试中采用“前置状态快照法”,在调用目标方法前,将网络中所有用户的关键状态(如金币数、关注列表、已看/未看视频集等)进行深层捕获或记录。
  • 方法执行完毕后,利用 Assert.assertEquals 逐项比对调用前后的全局快照,并调用 strictEquals 方法对用户对象进行深层二级状态比对 ,确保在任何正常路径或异常路径下,方法均未偷偷篡改内部容器或对象属性。

三、 三次作业的迭代过程分析

1. 业务逻辑的演进历程

  • 第一次作业:构建基础的社交拓扑网络。主要实现了用户(User)的加入、用户间关注与取关、以及基础视频的上传与基本观看功能,核心在于维护图的连通性与基础计数 。
  • 第二次作业:引入深层互动与硬币经济体系。系统新增了点赞、投币、转发、发送评论以及购买粉丝勋章等涉及多对象状态联动和复杂异常拦截的业务 。
  • 第三次作业:升级为智能推荐系统。新增了基于用户分区观看历史计算出的兴趣度模型,并引入了推荐视频、推荐特定排名的 UP 主、查询最具影响力 UP 主等涉及高权值计算的复杂图论与统计算法 。

2. 如何发现已有方法/容器在迭代中的变化?

  • 规格文本的静态 Diff 比对:在接到新一轮迭代需求时,首要任务是对比已有接口(如 UserInterface, NetworkInterface)的 JML 文本变化 ,观察已有方法的 assignable 副作用范围是否扩大,或者后置条件中是否追加了新的状态不变量。
  • 数据链路的依赖追溯:当新作业在类中引入新属性时(例如 HW3 中 User 新增了记录各分区观看频次的 typeCounts 数组) ,必须反向追溯哪些历史方法会隐式影响该属性。在本程序中,观看视频方法 watchVideo 在完成原本的增加历史记录逻辑之外,必须同步自增 typeCounts 对应分区的计数器。通过这种依赖分析,可以精准定位需要重构和补偿更新的历史方法。

3. 如何发现并攻克程序的性能瓶颈?

  • 识别瓶颈:审查 JML 中的量词嵌套。一旦发现 ensures 中存在多重 \forall\exists 嵌套对容器进行检索,如果在代码中直接使用嵌套循环,时间复杂度将飙升。此外,诸如最短路径查询 queryShortestPath 或最长递减序列 queryLongestDecSeq 这类图论计算,如果每次查询都从头遍历拓扑图,在面临高频指令输入时必然会导致 CPU 时间超时。
  • 攻克策略一:全局增量动态维护:对于高频查询方法(如 queryMutualFollowingSum) ,不采用即时遍历统计,而是通过在 followUserunfollowUser 发生时,以 $O(1)$ 复杂度动态累加/累减全局计数器 mutualFollowSum
  • 攻克策略二:记忆化缓存与脏标记机制:建立了独立的 NetworkGraph 类来接管图算法,设计了 bfsCache 字典和最长递减序列缓存。通过设置 isDecSeqDirty 脏标记,在拓扑结构发生破坏或改变的方法(如 addUserfollowUserunfollowUser)中统一调用 clearGraphCaches() 清空缓存,实现了高频查询下的“非必要不计算”。

四、 程序 Bug 分析与原因反思

  • Bug 1:“阴魂不散的视频”(集合元素删除不彻底)
  • 案发现场:在特定的测试点,一个视频被 UP 主发布后,又被多次 forward_video 转发给当前用户,导致 receivedVideos 列表中存在同一个视频 ID 的多个副本
  • 成因剖析:当调用 watch_video 时,常规的删除逻辑(如 List.remove(Object))只会删掉列表中匹配的第一个元素。这导致明明已经“观看”了视频,但列表中依然残留该视频的其他副本,最终触发 Expected "None" but got "101" 的断言失败。
  • Bug 2:“重叠字符串的幽灵”(关键字统计陷阱)
  • 案发现场:在实现 clean_spam_comments 统计垃圾评论中包含 keyword 的次数时,统计出的数量有时会少于预期。
  • 成因剖析:源于字符串匹配时的重叠计算问题。例如,当评论内容是 "ababab",关键字是 "aba" 时,常规的 replace 替换或单次跳跃查找只会将其算作 1 次或 2 次。但根据 JML 的遍历语义,重叠的部分必须被重复计算。
  • Bug 3:“异常优先级的交错”(多重前置条件冲突)
  • 案发现场:在带有多个参数检验的方法中,当遇到极端的失效测试用例时,代码抛出了错误的异常类型。
  • 成因剖析:未严格依照 JML signals 语句从上至下的次序编写 if-else。当低优先级异常和高优先级异常的触发条件同时成立时,由于判断分支的交错,错误地先拦截并抛出了低优先级异常。

五、 研讨课 JML“击鼓传花”游戏的感悟

在研讨课上开展的 JML“击鼓传花”规格传递游戏,给多人协作开发带来了极具工程价值的启示。

  • 发现了他人/自己 JML 的 Bug:在代码与规格的层层传递中,我发现由于书写者的疏忽,JML 规格中经常会出现 assignable 范围界定过宽或过窄、对空指针/空容器等边缘状态约束不全的漏洞。形式化语言一旦出现逻辑瑕疵,其破坏力比自然语言更大。

  • 需求与边界在传递中的语义变异:当需求链条被拉长,缺乏全局文档支撑时,每个参与者都会基于自己的隐式假设去解读前一个人的 JML。例如针对“智能推荐”在特定极端冷启动状态下的默认行为 ,各层传递人员由于没有对齐边界,导致最终的具体实现方案与原始设计初衷发生了巨大的语义偏移。

  • 多人组队编程时减少信息差、统一理解的工程措施

  1. 统一的领域词汇表与契约前置:在团队开发初期,严禁直接进入代码细节,必须先对全系统的核心业务领域概念、拓扑定义和全局约束建立统一的、无歧义的文字/形式化说明书。
  2. 测试驱动开发的协同强制化:消灭信息差最行之有效的手段,就是将自然语言需求和 JML 直接具象化为具体的测试用例。团队成员应在开发业务逻辑前,共同参与编写、评审 JUnit 的测试数据集。当大家对某个边界条件应该得到什么输出、抛出什么异常达成代码级别的共识后,理解上的偏差就彻底归零了。
  3. 严格的代码评审与持续集成约束:在代码合流时,强制实行非作者人员的契约一致性审查,确保每一个方法的修改都完美对齐 JML 约束,打破个人的思维盲区。
...全文
52 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

309

社区成员

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

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