OO第三次博客作业(第三单元总结)
(1)梳理JML语言的理论基础、应用工具链情况
Java 建模语言(JML)将注释添加到 Java 代码中,这样我们就可以确定方法所执行的内容,而不必说明它们如何做到这一点。有了 JML,我们就可以描述方法预期的功能,无需考虑实现。通过这种方法,JML 将延迟过程设想的面向对象原则扩展到了方法设计阶段。
JML的核心包括以下三个部分:
前置条件:requires
后置条件:ensures
副作用:assignable/modifiable
同时它也能够对程序的各种执行条件进行划分:normal_behavior/expectional_behavior
由于JML具有规范性,所以可以用JMLUnitNG/JMLUnit等工具生成测试用例,对相应的程序进行自动化测试。当然测试的正确性是有前提的:JML规格必须得写对了。
(2)【改为选做,能较为完善地完成的将酌情加分】部署SMT Solver,至少选择3个主要方法来尝试进行验证,报告结果
这部分先跳过吧。
(3)部署JMLUnitNG/JMLUnit,针对Graph接口的实现自动生成测试用例
在自己的电脑上根本没法部署。由于某个我不知道的原因,这个学期我的cmd上一直没法跑java,无论怎么改环境变量都不管用,连个
java -version
都识别不了,别说openJML,连上学期的logisim和Mars都跑不了。
这一部分暂时先咕掉,看看有没有什么其他的解决办法。
(4)按照作业梳理自己的架构设计,并特别分析迭代中对架构的重构
个人觉得这次作业不需要怎么画UML图了,因为实现的接口都是定死了的。整个单元作业的精髓在于各种实现方法的选择,包括但不限于数据结构(容器)、算法。
第一次作业开始,我就采用了讨论区里所一致推崇的双向HashMap存储点数关系的方法,这个方法在第一次作业中主要针对DISTINCT_NODE_COUNT指令,而从整单元作业来看,这个方法为本单元之后的两次作业打下了良好的基础。
在第一次作业中,我直接采用数组来作为Path的保存容器,后来简单起见改成了ArrayList。
第二次作业开始涉及图结构,对图结构的保存,我采用了可能稍微特别的方法:在上次作业保存的点集基础上,新增一个HashMap来保存边集,而遇到最短路径的计算时,再将点集和边集转化为邻接矩阵,运用DIjkstra算法求最短距离(现在想想这个转换是否有必要有待商榷),每跑一次Dijkstra算法可以算出n组点之间的最短距离,然后再用一个HashMap保存起来,用这种滚雪球的方法对抗时间复杂度。如果遇到增删,则在下次求最短距离时要把最短路径HashMap,邻接矩阵等内容进行更新(懒汉思想,不用就放着不管)。
第三次作业变成带权图,并且涉及换乘点的处理,复杂度进一步提升,牵扯到算法的选择。想到的第一种方法是,拆开每个换乘点,在换乘点间建立虚路径,对这些虚路径和实际存在的路径按要求赋相应的权值,完成各种不同的要求。但这样就涉及到了一个很要命的问题:极端情况下,换乘点可以高度重合(最极端的情况是所有路径全部重合,每个点都是换乘点,每个换乘点都可以换乘所有路线),这样的话图的点数就会爆炸,按普通Dijkstra算法的时间复杂度(O(n^2),n为点数)肯定是不行的,尽管可以做堆优化把复杂度降到O(mlogm)(m为边数),但一个现实问题是:没找到Java版的堆优化代码,现有的C++版代码又看的不是很懂,而且大多数采用的是邻接表存储,这意味着可能要对程序的图存储结构进行较大调整,怎么给每条线路拆分出一个换乘点并以合适方式进行表示也是个问题。
所以最后我采用了另一种方式,在各条路径内部计算出路径上两点之间的各种最小值,包括换乘次数(其实没有这个,因为恒为0),票价(其实就是最短距离),不满意度并存储,并存入图中,然后在矩阵初始化时用两点间最小值加上换乘相关的权值(比如最小换乘就是1,最低票价是2,最小不满意度是32),在跑完Dijkstra算法后在减去相应值,就能求出最后的结果。相比上一种做法,复杂度来源主要在于路径内部又跑了一遍Dijkstra,但由于一条路径上就那么些点,所以效率还可以,不过肯定不如第一种算法。(说白了因为菜写不出来好的实现,我写代码像cxk.gif)
(5)按照作业分析代码实现的bug和修复情况
第一次作业:最开始的反向HashMap采用的不是Path映射PathId,而是Path的Hash值映射PathId,这就导致了存在Hash值重复的情况,虽然过了强测但互测被Hack一次。后来利用instanceof关键词重写了equals方法消除了Bug,也为后两次作业打下了正确的基础。
第二次作业:没Bug,表现不错。
第三次作业:灾难。由于对两条路径纠缠在一起的情况没有考虑到,导致初始化的时候出现问题(正常应该存两点间最小值,但我忽略了这种情况,按两点间只有一个值写的代码,导致这个值被错误刷新),另外还有一处明显的手误没看出来,在中测一遍过的情况下,强测10分,互测被Hack19次。但Bug越多,往往也意外着错误越明显、越简单,总共37个Bug被一次性修复,也算是一个尴尬的纪录了。
(6)阐述对规格撰写和理解上的心得体会
在写这次作业之前,我看到有人的作业中提出JML比较适合大型程序的结构描述,但我并不这么认为,因为从这几次的作业和课上实验来看,每次给出的JML规格都存在或多或少的错误,这就说明了一个问题:用JML语言准确描述代码要做什么,并不是一件容易的事情,代码越复杂,描述起来的难度就越大。具体到作业中,JML代码描述一些规模较小、功能较简单的方法还是比较容易的,但描述一些功能复杂、规模较大的方法则显得力不从心,比如最后一次作业中实现的Graph类中几个查找函数,与其从冗长且可能存在Bug的JML描述中进行对照,不如直接从指导书get到函数的实现要点。
再者说,JML的一个好处是没有限制实现方式,但这种没有限制实现方式的情况在实际的工业生产与大型程序设计中并不多见。以我们亲爱的OS实验课为例(当然OS肯定不会用Java写,这里仅仅做一个假设),在OS的课程中,每个函数之间的调用关系都非常紧密和复杂,JML代码能不能写对都是问题,即使写对了,在函数体内部,每个函数所执行的流程都非常固定,很难有自由发挥的空间,这种情况下,写一份JML描述几乎和写出程序代码无异!比如下面的函数,我想不出如果用JML能描述出什么花样来,更想不出写出的JML和程序代码能有多大区别:
15 u_int
16 diskaddr(u_int blockno)
17 {
18 if ( super && blockno > (super->s_nblocks)) {
19 user_panic("diskaddr failed!");
20 }
21 return DISKMAP+blockno*BY2BLK;
22 }
JML能胜任的情况,也就是在一些中小型程序(比如这种作业)中,程序员能够决定整个程序所采用的架构(尤其是数据结构)的情况下来描述程序,因为这种情况下是真正的只在意功能的正确性而不在乎如何实现,而在稍微大型的系统(比如OS的小操作系统,实际上它也没那么大)中,架构已经定的死死的,就很难有JML发挥的余地,这时候就只能用自然语言描述方法所期望的功能,然后由程序员套用现有的架构来实现功能。这种情况实际上在本单元的后两次作业中就体现了出来,在第一次作业后,Path,和PathContainer中的相关容器已经确定,这时候再看JML中的描述,就要在头脑内将其翻译成用我们对应的容器的实现方式,与其做这样烧脑的翻译工作,还不如直接看指导书的自然语言描述然后实现来得快呢。倒是描述一些边界、异常情况时,JML的准确性还算是起到了一点帮助。
另外说到准确性,从作业和实验课JML多次的改动中,就能看出一个致命的问题:用规格来确保程序的正确性,那么用什么来确保规格的正确性呢?
(说起来课程组可以考虑组织一次关于JML的辩论,效果绝对好)
但除开JML,我在第三次作业的一堆Bug中,深刻体会到了测试的重要性。因为测试不够强(不管是自己做的测试还是提交的中测),我强测只拿了10分,互测被各种Hack了19次(最后这37个样例被一波带走是最骚的)。虽然也尝试过用JUnit来进行测试,但还是没能想到初始化的可能情况,因而也构造不出复杂的样例。从这里就能看出随机测试的必要性,它能覆盖程序员没注意到的地方,对意想不到的Bug进行发现。所以,感觉测试程序的重要性真的不亚于写出程序。但每次写完作业后,总是感觉测试的时间和精力不够,这个问题一直困扰着我,说到底还是希望能够好好实践一下测试方法,尤其是随机测试的方法。
OO第三次博客作业(第三单元总结)的更多相关文章
- OO第三次博客作业--第三单元总结
一.JML 语言的理论基础及应用工具链 JML 是一种行为接口规格语言,提供了对方法和类型的规格定义手段.通过 JML 和其支持工具,不仅可以基于规格自动构造测试用例,并整合了 SMT Solver ...
- OO第四次博客作业--第四单元总结及课程总结
一.总结第四单元两次作业的架构设计 1.1 第一次作业 类图如下: 为了突出类.接口.方法.属性.和参数之间的层次结构关系,我为 Class 和 Interface 和 Operation 分别建立了 ...
- [BUAA OO]第三次博客作业
OO第三次博客作业 1. 规格化设计的发展 我认为,规格化设计主要源自于软件设计的两次危机.第一次是由于大量存在的goto语句,让当时被广泛应用的面向过程式的编程语言臃肿不堪,在逻辑性上与工程规模上鱼 ...
- OO第三次博客作业——规格
OO第三次博客作业——规格 一.调研结果: 规格的历史: 引自博文链接:http://blog.sina.com.cn/s/blog_473d5bba010001x9.html 传统科学的特点是发现世 ...
- OO第四次博客作业!
oo第四次博客作业 一.测试与正确性论证比较 测试只是单方面片面的证明对于当前的输入程序是正确的,测试只能证明程序有错误,不能说明程序是对的. 正确性论证是程序达到预期目的的一般性陈述,是通过规范化的 ...
- OO第4次博客作业
OO第4次博客作业 一.第4单元设计 第四单元主要围绕UML图的结构进行JAVA代码编写,对JAVA的层次结构进行更多的认识.个人认为编程操作在实质上与上一章的PathContainer有许多的相同之 ...
- [2017BUAA软工]第三次博客作业:案例分析
第三次博客作业:案例分析 1. 调研和评测 1.1 BUG及设计缺陷描述 主要测试博客园在手机端上的使用情况. [BUG 01] 不能后退到上一界面(IOS) 重现步骤:打开博客首页中任意博文,点击博 ...
- OO第二次博客作业(第二单元总结)
在我开始写这次博客作业的时候,窗外响起了希望之花,由此联想到乘坐自己写的电梯FROM-3-TO--1下楼洗澡,然后······ 开个玩笑,这么辣鸡的电梯肯定不会投入实际使用的,何况只是一次作业.还是从 ...
- OO第四次博客作业(第四单元作业及期末总结)
(注意:本文写作顺序与作业要求不完全一致,但涵盖了作业的所有要求) 一学期的BUAA特色OO课程结束了. PART 1 我想先写我这一学期的感想 从第一单元满怀期待地写完多项式求值到最后看着60分不 ...
- 第三周博客作业<西北师范大学|李晓婷>
1.助教博客链接:https://www.cnblogs.com/lxt-/MyComments.html 2.学生作业打分要求: https://www.cnblogs.com/nwnu-dai ...
随机推荐
- Java 石家庄铁道大学软件工程系 学生学籍管理系统 2019 版
本系统的作用是简单实现一些学生成绩管理操作:录入,修改,绩点计算,以及系统退出等. 首先建一个主函数实现界面的实现,然后建一个数据类用来定义存放数据.之后建立一个工具类,用来实现所有要进行的操作.首先 ...
- 修复GRUB引导故障!
故障原因:MBR中的GRUB引导程序遭到破坏,grub.conf文件丢失,引导配置有误 故障现象:系统引导停滞,显示“grub>”提示符 解决思路:若无MBR备份,进入急救模式,重新安装grub ...
- mysql yum源安装极速
mysql yum源地址:https://dev.mysql.com/downloads/repo/yum/ 随便找个最新的不管你是要装任何个历史版本他都可以,后面我会介绍: 安装第一步预置环境清理: ...
- 前端学习 之 JavaScript 之 JSON
一.JSON的简介 1.什么是JSON JSON 英文全称 JavaScript Object Notation JSON 是一种轻量级的数据交换格式. JSON是独立的语言 * JSON 易于理解. ...
- tomcat8配置了tomcat-users.xml,报403 Access Denied
配置了tomcat-users.xml之后,重启tomcat服务,仍然访问拒绝. 原因:tomcat8.5 更改之后,仍然访问拒绝. 还需步骤如下: vi /usr/local/tomcat/apac ...
- 设计模式课程 设计模式精讲 3-7 接口隔离原则讲解及Coding
1 主讲内容 1.1 核心内容 1.2 优点 1.3 课程记录 2 代码演练 2.1 接口隔离原则反比 2.2 接口隔离原则正比 1 主讲内容 1.1 核心内容 总结:细粒度可以进行再组装,粗粒度不可 ...
- LIBRA查询
SELECT COUNT(1)FROM rawdata_vehiclepassing xWHERE x.passingtime >= to_date('2019-11-24,00:00:00', ...
- Windows远程“要求的函数不受支持”解决办法
解决方法: 开启组策略中远程桌面链接安全层.1.开始-运行-gpedit.msc,进入组策略编辑器:2.找到左侧边栏计算机配置-管理模板-Windows组件-远程桌面服务-远程桌面会话主机-安全项:3 ...
- spring boot 整合 Camunda
官网:https://camunda.com/ 论坛:https://forum.camunda.org/ 一. 创建 spring boot 项目,添加项目依赖 <?xml version=& ...
- jQuery常用操作(待续)
1. input清空内容 <1> $("#选择器id").val(""); <2> $("input[name='input框 ...