OO-Unit3-博客总结

刘梦琨-24231215 2026-05-28 16:45:35

OO-Unit3-博客总结

面向对象Unit3主要是针对JML进行规格驱动开发。本次作业围绕模拟bilibili用户、视频、网络交互环境进行设计。根据助教给出的JML规格实现具体方法,完成一个简单的bilibili用户系统。重点考察了与图有关的算法。此外,作业还需要按照JML要求比那些Junit测试进行检测,保证相应方法严格按照JML要求实现。


JML规格开发的理解

  • 整体感受
    JML(Java Modeling Language)是面向Java的行为接口规格语言,以形式化注释描述类、方法的规格。通过JML,实现规格与实现分离,开发时可以专注于方法本身的实现细节,而不必担心方法的逻辑正确性。
  • JML核心行为
  1. 前置条件(Preconditions):方法被调用前必须满足的条件。
    @requires x > 0; // 前置条件:参数x必须大于0
    
  2. 后置条件(Postconditions):方法执行后必须满足的条件。
    @ensures \result > 0; // 后置条件:返回值必须大于0
    
  3. 不变式(Invariants):类的状态必须始终满足的条件。
    @invariant \forall int i,j; 0 <= i && i < j && j < users.length; !users[i].equals(users[j]); // 不变式:用户数组中没有重复用户
    
    JML的核心在于规定方法的行为规范,确保方法在满足前置条件的情况下正确执行,并且在执行后满足后置条件。同时,不变式保证了类的状态始终处于合法范围内。
  • JML与开发
    JML的使用使得开发更加规范化。通过明确的规格定义,我们只需重点关注方法的实现细节即可。但是作为初学者,在一开始的作业中,我对于JML的理解也出现了误差,错误将JML规范当成了方法的具体实现细节。JML的核心在于规定方法的行为规范,而不是具体的实现细节。只要方法满足了JML的前置条件和后置条件,以及相应的不变式,就可以有多种实现方式。JML只规定了方法的行为规范,而不限制具体的实现细节。这种分离使得开发更加灵活,但也需要开发者正确理解JML的核心概念,避免将其误解为具体的实现细节。

JML与Junit测试

前文提到,JML重点在于规定方法的行为规范,而Junit测试则是用来验证方法是否满足这些规范。通过编写Junit测试,我们可以模拟各种输入情况,验证方法在不同条件下的行为是否符合JML的要求。Junit测试可以帮助我们发现方法实现中的潜在问题,确保方法在满足前置条件的情况下正确执行,并且在执行后满足后置条件。

  • 不定式的测试
    不定式是类的状态必须始终满足的条件。在Junit测试中,我们可以通过模拟不同的用户操作,验证类的状态是否始终满足不定式。
  • 前置条件的测试
    前置条件是方法被调用前必须满足的条件。当相应的前置条件不满足时,方法应该抛出相应的异常。在Junit测试中,我们可以模拟不同的输入情况,验证方法在前置条件不满足时是否正确抛出异常。
  • 后置条件的测试
    后置条件是方法执行后必须满足的条件。主要是验证对应的方法是否真正实现了JML规范中要求的作用。
  • pure的针对测试
    pure方法是指那些没有副作用的方法,即不会修改对象的状态。同时也是作业考察的重点。在每一次的作业中,课程组都给予了对应的strictEqual()方法用来测试pure方法的正确性。需要明确方法的副作用,对于作用对象的其它属性应该严格保证不变。

程序迭代与性能分析

在本单元的三次作业迭代中,系统逐步引入了更多类型的对象(如从单纯的用户和视频,到加入评论、硬币、勋章等)以及更复杂的网络关系查询和异常处理机制。这一过程不仅考察了对JML规格的实现,更对程序的性能提出了较高的要求。如果完全照搬规格中描述的逻辑(如多重嵌套\forall\exists遍历),必定会导致TLE(超时错误)。因此,需要在遵循JML规格的基础上,选择合适的数据结构与算法,并在适当的地方进行状态维护与缓存。

  • 第九次作业
    性能分析与优化:
    初次作业中涉及了部分网络连接关系的查询。按照JML的描述可能是要求遍历图中的路径,一旦直接使用DFS或者BFS每次重新搜索,复杂度会极高。主要的优化策略是新建一个变量来实时统计用户相互关注的总数。通过对变量的维护(在用户关注/取关时更新),查询时直接返回该变量的值,从而将查询复杂度从$O(N)$降低到$O(1)$。

  • 第十次作业(系统功能的扩展)
    性能分析与优化:
    随着系统体系的复杂化,出现了一些特定统计值的频繁查询指令。如果采用“查时再算”的全量遍历策略,无疑会面临巨大的时间开销。我在相关类中引入了额外的缓存变量(例如计算某个视频的交互总热度等)。当发生修改相关属性的指令时,同步更新对应的缓存变量;在查询方法被调用时直接返回该缓存值,从而将原本$O(N)$的查询转化为$O(1)$。不过这种优化只会在反复查询且数据未改变的情况下有效。

  • 第十一次作业(深入计算与高阶应用)
    性能分析与优化:
    在此阶段处理涉及到图的最短路或者具有权重的路径搜索时,直接BFS已经不能满足要求。此时需要应用到图算法领域的经典算法。如果是带权图的最短路径搜寻,通过结合使用PriorityQueue实现堆优化的Dijkstra算法,能够有效地减少无效的边扩展,保持算法良好的时间上界。


JML游戏感悟

在游戏中,初次编写自然语言用于描述问题是比较简单的,但是如果自然语言没有严格规定相应的实现要求,会导致编写JML十分困难。需要在编写JML时,自己理解自然语言的意思,理清相应的逻辑关系,总结出前置条件、后置条件以及不变式等内容。才能正确编写出相应的JML。

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

309

社区成员

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

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