2021年春季学期
计算学部《软件构造》课程
Lab 2实验报告
姓名 |
郭子正 |
学号 |
1190201117 |
班号 |
1936601 |
电子邮件 |
1190201117@stu.hit.edu.cn |
手机号码 |
18102152791 |
目录
2 实验环境配置
3 实验过程
3.1 Poetic Walks
3.1.1 Get the code and prepare Git repository
3.1.2 Problem 1: Test Graph <String>
3.1.3 Problem 2: Implement Graph <String>
3.1.3.1 Implement ConcreteEdgesGraph
3.1.3.2 Implement ConcreteVerticesGraph
3.1.4 Problem 3: Implement generic Graph<L>
3.1.4.1 Make the implementations generic
3.1.4.2 Implement Graph.empty()
3.1.5 Problem 4: Poetic walks
3.1.5.1 Test GraphPoet
3.1.5.2 Implement GraphPoet
3.1.5.3 Graph poetry slam
3.1.6 使用Eclemma检查测试的代码覆盖度
3.1.7 Before you’re done
3.2 Re-implement the Social Network in Lab1
3.2.1 FriendshipGraph类
3.2.2 Person类
3.2.3 客户端main()
3.2.4 测试用例
3.2.5 提交至Git仓库
4 实验进度记录
5 实验过程中遇到的困难与解决途径
6 实验过程中收获的经验、教训、感想
6.1 实验过程中收获的经验和教训
6.2 针对以下方面的感受
1 实验目标概述
本次实验训练抽象数据类型(ADT)的设计、规约、测试,并使用面向对象 编程(OOP)技术实现 ADT。具体来说:
⚫ 针对给定的应用问题,从问题描述中识别所需的 ADT;
⚫ 设计 ADT 规约(pre-condition、post-condition)并评估规约的质量;
⚫ 根据 ADT 的规约设计测试用例;
⚫ ADT的泛型化;
⚫ 根据规约设计 ADT 的多种不同的实现;针对每种实现,设计其表示
(representation)、表示不变性(rep invariant)、抽象过程(abstraction
function)
⚫ 使用 OOP 实现 ADT,并判定表示不变性是否违反、各实现是否存在表
示泄露(rep exposure);
⚫ 测试 ADT 的实现并评估测试的覆盖度;
⚫ 使用 ADT 及其实现,为应用问题开发程序;
⚫ 在测试代码中,能够写出 testing strategy 并据此设计测试用例。
2 实验环境配置
简要陈述你配置本次实验所需环境的过程,必要时可以给出屏幕截图。
特别是要记录配置过程中遇到的问题和困难,以及如何解决的。
由于无法访问MIT代码仓库,于是从实验指导上指定的地址下载代码。之后从GitHub克隆空项目到本地,将代码添加进工程。最初遇到错误,经检查发现是MIT练习题的文件路径和实验报告不一致、添加进工程时未完全更改导致的。
在这里给出你的GitHub Lab2仓库的URL地址(Lab2-学号)。
3 实验过程
请仔细对照实验手册,针对三个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。
3.1 Poetic Walks
利用前期建立好的Graph类实现一个小应用,先由给定的语料库建立一张有向图,再用另外给定的输入和建立好的图,根据题目要求生成新的文本。
3.1.1 Get the code and prepare Git repository
由于无法访问MIT的代码仓库,所以改从另外指定的地址下载。远程新建仓库之后,克隆到本地,并将下载的代码添加进去。用eclipse配置好开发环境即可。
3.1.2 Problem 1: Test Graph <String>
以下各部分,请按照MIT页面上相应部分的要求,逐项列出你的设计和实现思路/过程/结果。
写测试用例。每个测试方法都首先生成了一张图,再用各种方法进行测试。
testAdd:新建一张图,每增添一个点都检测add()的返回值,并且用查看器检查是否真的增加了一个顶点。随机移除某些点再重新添加,重复添加某些点并查看这些情况下add()返回值是否符合预期,对图的修改是否达到预期。
testSet():随机设置边权,调用Set()时检查返回值是否符合预期、是否真的对边进行了修改(weight>0,weight<0,weight=0),去除某些边、重复添加某些边再进行测试。
testRemove():建好图之后删除某些点(有些点删除不止一次),查看每次删除时函数的返回值,用查看器查看对图的修改是否符合预期。
testVertices(),testSources(),testTargets():动态维护答案,对图不断修改的同时对预期答案也不断修改,随时调用Vertices()查看图中顶点情况是否符合预期。
3.1.3 Problem 2: Implement Graph <String>
以下各部分,请按照MIT页面上相应部分的要求,逐项列出你的设计和实现思路/过程/结果。
3.1.3.1 Implement ConcreteEdgesGraph
建立Edge类:
SPEC,AF,RI,REP如下:
主要维护起点、终点和权值。重写了toString,equals,hashCode方法。
实现ConcreteEdgesGraph类:
SPEC,AF,RI,REP如下:
set实现思路:首先确定weight的值以确定行为,如果遇到非法输入直接返回0;如果weight=0且待删除的边的任意顶点不存在则什么也不干,返回0;如果weight>0,先删除旧边(没有则不删)再添加新边(如果顶点不在图中也自动添加)。
remove实现思路:搜边并删除,没有则不删。
source,targets实现思路:遍历edges并返回符合要求的边的相应顶点即可。
3.1.3.2 Implement ConcreteVerticesGraph
Vertex类实现思路:
SPEC,AF,RI,REP如下:
重写了toString,equals,hashCode方法。该类通过存放顶点名称和出边来存放顶点信息。
ConcreteVerticesGraph类实现思路:
SPEC,AF,RI,REP如下:
add设计思路:直接添加顶点。
set设计思路:非法输入直接返回;添加边时先保证顶点都在图中(如果不是先添加缺失的顶点),再修改这条边出发的源头(from)的出边信息。删除边时直接修改源头顶点的出边信息。
remove设计思路和set设计思路有重叠,是它的一部分。
sources设计思路:扫描全部顶点,找到符合要求的部分并输出。
targets设计思路:直接返回传入顶点的出边信息即可。
3.1.4 Problem 3: Implement generic Graph<L>
3.1.4.1 Make the implementations generic
将对应的String替换成L即可。
3.1.4.2 Implement Graph.empty()
3.1.5 Problem 4: Poetic walks
3.1.5.1 Test GraphPoet
测试几种情况:文件不存在、文件为空、文件只包含大写字母、只包含小写字母、正常的英文句子、全部为符号。
3.1.5.2 Implement GraphPoet
直接按题目要求模拟即可。建图时根据每个先后关系确定边,获取边的权值,再将对应边的权值加一。生成诗句时在图中搜寻对应边即可。如果有多个中间顶点满足权值加和最大的条件,任意取一个中间顶点即可。
3.1.5.3 Graph poetry slam
设计语料库,显示“三点几,饮茶先”。
3.1.6 使用Eclemma检查测试的代码覆盖度
3.1.7 Before you’re done
请按照http://web.mit.edu/6.031/www/sp17/psets/ps2/#before_youre_done的说明,检查你的程序。
如何通过Git提交当前版本到GitHub上你的Lab2仓库。
git add->commit->push
在这里给出你的项目的目录结构树状示意图。
3.2 Re-implement the Social Network in Lab1
建立一个有向图模型表示人际关系。人与人之间的距离用有向图中从一 方到达另一方经过的最小边数确定。并且人们的名字不能重复。
3.2.1 FriendshipGraph类
直接保存人的集合和表示人际关系的有向图。用BFS来计算人与人之间的距离。
3.2.2 Person类
保存姓名,提供获取姓名的方法。
3.2.3 客户端main()
建立一张FriendshipGraph,运行实验一的样例。
3.2.4 测试用例
3.2.5 提交至Git仓库
如何通过Git提交当前版本到GitHub上你的Lab3仓库。
git add->commit->push
在这里给出你的项目的目录结构树状示意图。
4 实验进度记录
请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。
每次结束编程时,请向该表格中增加一行。不要事后胡乱填写。
不要嫌烦,该表格可帮助你汇总你在每个任务上付出的时间和精力,发现自己不擅长的任务,后续有意识的弥补。
日期 |
时间段; |
计划任务 |
实际完成情况 |
2021-06-01 |
13:45-15:00 |
开始写Graph<String>测试用例 |
完成一半 |
2021-06-03 |
22:45-23:00 |
继续写Graph<String>测试用例 |
按计划完成 |
2021-06-04 |
19:00-22:16 |
写ConcreteEdgesGraph的测试用例,并实现这个类 |
按计划完成 |
2021-06-04 |
22:30-24:00 |
设计Vertex类的spec |
按计划完成 |
2021-06-05 |
10:00-18:39 |
继续完成ConcreteEdgesGraph |
本应该很早就完成,结果写到后面发现spec设计有问题,推倒重写反复三次。最终完成。 |
2021-06-05 |
19:00-20:00 |
完成3.1 |
按计划完成 |
2021-06-05 |
22:00-24:00 |
完成3.2 |
发现不能有警告,但是equals方法用到了强制类型转换,而object转其他类似乎必定会警告,遂百思不得其解。十二点钟终于百度到答案。 |
2021-06-06 |
21:00-22:00 |
完成MIT Problem Set上的题目 |
按计划完成 |
2021-06-08 |
13:45-15:30 |
完成剩下的内容 |
按计划完成 |
5 实验过程中遇到的困难与解决途径
遇到的难点 |
解决途径 |
object进行强制类型转换会弹出unchecked cast警告 |
百度,虽然大多数答案都是互相抄的,还都不管用,但是终于找到了能用的方案 |
无法识别某个文件夹是一个包 |
问学长被骂之后发现,IDE设置中将该文件夹排除了。更改设置即可。 |
|
|
6 实验过程中收获的经验、教训、感想
6.1 实验过程中收获的经验和教训
工程进行之初应详尽考虑并设计规约,以避免之后返工的情况。
6.2 针对以下方面的感受
(1) 面向ADT的编程和直接面向应用场景编程,你体会到二者有何差异?
面向ADT编程更加灵活,可以适应不同场合,仅需要对代码进行微小改动。
(2) 使用泛型和不使用泛型的编程,对你来说有何差异?
使用泛型可以使ADT不依赖于实际类型,增大了ADT的适用范围,减小了工作量。
(3) 在给出ADT的规约后就开始编写测试用例,优势是什么?你是否能够适应这种测试方式?
遵循了“早出错”原则,可以尽早发现错误并且改正,减小损失。我可以适应这种方式。
(4) P1设计的ADT在多个应用场景下使用,这种复用带来什么好处?
这种复用可以减少开发成本:当ADT应用在不同场合时仅需要进行微小调整,从而降低开发成本;发现ADT出错时仅需要对ADT本身进行调整而无需对每个具体应用都进行改动,从而降低调试成本。
(5) P3要求你从0开始设计ADT并使用它们完成一个具体应用,你是否已适应从具体应用场景到ADT的“抽象映射”?相比起P1给出了ADT非常明确的rep和方法、ADT之间的逻辑关系,P3要求你自主设计这些内容,你的感受如何?
除了没在实验指导里发现P3之外感觉都还好。
(6) 为ADT撰写specification, invariants, RI, AF,时刻注意ADT是否有rep exposure,这些工作的意义是什么?你是否愿意在以后编程中坚持这么做?
这些工作的给ADT定义了统一的内部规范,方便今后持续开发,防止忘记ADT最初设计的细节以及相应方法。时刻检查rep暴露可以提高安全性和稳定性。我愿意。
(7) 关于本实验的工作量、难度、deadline。
适中。
(8) 《软件构造》课程进展到目前,你对该课程有何体会和建议?
还是应该多写代码。