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 ...
随机推荐
- 人工神经网络(从原理到代码) Step 01 感知器 梯度下降
版权声明: 本文由SimonLiang所有,发布于http://www.cnblogs.com/idignew/.如果转载,请注明出处,在未经作者同意下将本文用于商业用途,将追究其法律责任. 感知器 ...
- Ubantu 固定IP
ubantu固定IP设置 1.以root身份登录 2. vi /etc/network/interfaces 参照截图修改,保存退出 3.刷新接口,重启服务 /etc/init.d/networkin ...
- php基础 php 全局变量
$_GET ----->get传送方式 $_POST ----->post传送方式 $_REQUEST ----->可以接收到get和post两种方式的值 $GLOBALS ---- ...
- python中 with 的作用
with是 Python2.5 引入的一个新语法,它是一种上下文管理协议,目的在于从流程中吧 try...except 和 finally 关键字和资源释放相关代码统统去掉,简化 try...exce ...
- VUE学习笔记二
package.json不可以写注释!!!!!!!!!!初始化:npm init -y 有时候使用 npm i node-sass -D 装不上,这时候,就必须使用 cnpm i node-sass ...
- nginx 缓存
浏览器缓存与nginx缓存 浏览器缓存 优点:使用有效缓存时,没有网络消耗,速度快:即使有网络消耗,但对失效缓存使用304响应做到网络消耗最小化 缺点:仅提升一个用户的体验 nginx 缓存 优点:提 ...
- 吴裕雄--天生自然ORACLE数据库学习笔记:优化SQL语句
create or replace procedure trun_table(table_deleted in varchar2) as --创建一个存储过程,传入一个表示表名称的参数,实现清空指定的 ...
- 吴裕雄--天生自然ORACLE数据库学习笔记:管理表空间和数据文件
col tablespace_name for a10 col file_name for a50 col bytes ,, select tablespace_name,file_name,byte ...
- GitHub 网站汉化
居然是一个中文Github网站!该不会是个假的吧? 2018-09-03 17:30 前几天分享了一篇文章——3个搜索技巧!在 GitHub上快速找到实用资源!眼尖心细的读者发现了文中的Github网 ...
- python爬虫(四) 内涵段子
import requests import time import json from urllib import request from urllib import parse url = 'h ...