2022年春季学期
计算学部《软件构造》课程
Lab 2实验报告
姓名 | 曲之晨 |
学号 | 120L020113 |
班号 | 2003003 |
电子邮件 | fruitcereal.qzc@gmail.com |
手机号码 | 18057787837 |
3.1.1 Get the code and prepare Git repository· 2
3.1.2 Problem 1: Test Graph <String>· 2
3.1.3 Problem 2: Implement Graph <String>· 4
3.1.3.1 Implement ConcreteEdgesGraph· 4
3.1.3.2 Implement ConcreteVerticesGraph· 4
3.1.4 Problem 3: Implement generic Graph<L>· 5
3.1.4.1 Make the implementations generic· 5
3.1.4.2 Implement Graph.empty()· 5
3.1.5 Problem 4: Poetic walks· 5
3.1.5.2 Implement GraphPoet· 5
3.1.5.3 Graph poetry slam··· 6
3.1.6 使用Eclemma检查测试的代码覆盖度··· 6
本次实验训练抽象数据类型(ADT)的设计、规约、测试,并使用面向对象
编程(OOP)技术实现 ADT。具体来说:
l 针对给定的应用问题,从问题描述中识别所需的 ADT;
l 设计 ADT 规约(pre-condition、post-condition)并评估规约的质量;
l 根据 ADT 的规约设计测试用例;
l ADT 的泛型化;
l 根据规约设计 ADT 的多种不同的实现;针对每种实现,设计其表示
(representation)、表示不变性(rep invariant)、抽象过程(abstraction
function)
l 使用 OOP 实现 ADT,并判定表示不变性是否违反、各实现是否存在表
示泄露(rep exposure);
l 测试 ADT 的实现并评估测试的覆盖度;
l 使用 ADT 及其实现,为应用问题开发程序;
l 在测试代码中,能够写出 testing strategy 并据此设计测试用例。
大部分实验环境已经在LAB1配置完毕。
本次实验需要在 Eclipse IDE 中安装配置 EclEmma(一个用于
统计 JUnit 测试用例的代码覆盖度的 plugin)。
但我用的是IDEA
在这里给出你的GitHub Lab2仓库的URL地址(Lab2-学号)。
https://github.com/ComputerScienceHIT/HIT-Lab2-120L020113
请仔细对照实验手册,针对三个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。
实现一个图graph的模块,基于此模块,根据语义库进行诗歌创作
1.实现Graph的String类型接口类,之后将String拓展为泛型L类;
2.创建Graph类的add、set、remove、vertices、sources、targets等方法;
3.基于创建好的Graph类,实现GraphPoet类,将语义库存入graph图中,然后利用GraphPoet类,根据graph中语义库的信息,对输入文本进行处理,若输入文本的两个单词之间存在桥接词,则插入桥接词;若存在多个单一桥接词,则选取边权重较大者。最终得到由输入文本创作的诗歌理解。
获取:git clone
创建:git init
上传:git add .
git commit –m ”*commit*”
git push
-
-
- Problem 1: Test Graph <String>
-
对Graph接口中方法的测试策略大致可以阐述如下:
1) 将图划分为空图与非空图
2) 将图中用于测试的顶点分为两组,一组已经存在于图中,另一组不存在于图中。
3) 将图中用于测试的边根据端点在图中的存在性和边权的性质分组,根据端点存在性分为“两点存在”、“只有一点存在”和“两点不存在”三组;根据边权的性质将边分为“边权为0”和“边权为正整数”两组;
具体测试策略
-
-
- Problem 2: Implement Graph <String>
-
以下各部分,请按照MIT页面上相应部分的要求,逐项列出你的设计和实现思路/过程/结果。
-
-
-
- Implement ConcreteEdgesGraph
-
-
3.1.3.1.1 Edge的设计&测试:
一个起点,一个终点,边的权值。
其中拥有三个observe函数:
直接返回所需要的值就行
一个equals函数:
如果起点和终点都相同,则视作一条边
一个重写的toString函数:
式为”*sourece*-*weight*->target”,checkRep函数
一个checkRep函数:
保证权值大于等于零,起点和终点不相等且不为空即可。
测试参见problem1的思路
3.1.3.1.2 ConcreteEdgesGraph的设计&测试:
顶点集和边集
时刻保证边集中的所有边没有相同的起点和终点即可
- add(String vertex):
先检查点集中是否有该点,没有就添加,有就直接返回
- set(String source, String target, int weight):
先判断是删除还是新增&更改
再看点是否存在,不存在就先加入点集
最后再看是更改还是新增
- remove(String vertex):
先检查点集中是否有该点,有就删除,没有就直接返回
- vertices()&sources(String target)& targets(String source):
这仨都差不多,值得注意的就是第一个需要做防御式拷贝
- toString():
格式为边集中所有边的toString,每条边以\n相隔。
测试参见problem1的思路
把接口和里面的方法都改成这样就行了:
-
-
-
- Implement Graph.empty()
-
-
如此修改即可:
-
-
- Problem 4: Poetic walks
- Test GraphPoet
- Problem 4: Poetic walks
-
参见problem 1;
多测试一个toString就行
需要注意的是我设计的GraphPoet类中语料库禁止为空
-
-
-
- Implement GraphPoet
-
-
- 读入语料库,分割语料库
- 循环,每次将两个挨着的词通过set加入图中,忽略前后相同的单词
- 如果已经存在,则把权值加1
插入桥词的函数就遍历前点的终点集,后点的起点集,取交集后插入权值最大的词就行了。
符合预期,很给力
-
-
- 使用Eclemma检查测试的代码覆盖度
-
平均接近100%,相当喜人
请按照Problem Set 2: Poetic Walks的说明,检查你的程序。
如何通过Git提交当前版本到GitHub上你的Lab2仓库。
git add .
git commit –m “*commit*”
git push
在这里给出你的项目的目录结构树状示意图。
重构LAB1中的FriendshipGraph类和Person类,且尽量利用graph的方法
只需要一个以Person为顶点的图
addvertex就利用graph.add()
addedge就利用graph.set()
getdistance没什么好改的,把里头获取朋友列表改成graph.target()即可
只保留name就行了,friendship可以删掉了
重写了equals方法
-
-
- 客户端main()
-
正常运行,输入点集与关系,测试一下distance是否算对即可。
-
-
- 测试用例
-
- normalTest:测试能否正常运行
- exceptionTest:测试重名是否会报错:
- distanceTest:测试能否正确输出最短路径:
-
-
- 提交至Git仓库
-
如何通过Git提交当前版本到GitHub上你的Lab3仓库。
git add .
git commit –m “*commit*”
git push
在这里给出你的项目的目录结构树状示意图。
请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。
每次结束编程时,请向该表格中增加一行。不要事后胡乱填写。
不要嫌烦,该表格可帮助你汇总你在每个任务上付出的时间和精力,发现自己不擅长的任务,后续有意识的弥补。
日期 | 时间段 | 计划任务 | 实际完成情况 |
2022.5.15 | 8:00-12:00 | P1.problem123 | 按计划进行 |
2022.5.15 | 13:00-18:00 | P1.problem4 | 按计划进行 |
2022.5.15 | 19:00-23:00 | P2 | 按计划进行 |
遇到的难点 | 解决途径 |
任务要求全是英文看的眼晕 | 使用google翻译 |
程序有bug难以发现 | 使用debug |
代码覆盖率上不去 | testvertex里别用graph.empty,用emptyInstance() |
- 自学能力极其重要。
- 英语能力极其重要。
- 不要一上手就瞎写,数据类型都选不对,直接重来。
- 要多多注意问题的边界条件。
- 面向ADT的编程和直接面向应用场景编程,你体会到二者有何差异?
ADT:有一个非常明显的好处,可复用性对编程效率有极大提升。
直接面向应用场景编程:虽然可能可以做到更为灵活的编程策略,但其中代码或函数的可复用性比起ADT而言没有显著优势,甚至在某些情况下由于可复用性不够好导致程序的后续开发和维护遇到困难。
- 使用泛型和不使用泛型的编程,对你来说有何差异?
使用泛型编程可以极大提高开发效率、减少代码重复性
- 在给出ADT的规约后就开始编写测试用例,优势是什么?你是否能够适应这种测试方式?
优势:不会受写完代码后的主观影响制约,仅仅面向规约编写测试。适合多人协同。
尽量适应。
- P1设计的ADT在多个应用场景下使用,这种复用带来什么好处?
减少代码重复性、更加简洁美观、模块化思想强
- P3要求你从0开始设计ADT并使用它们完成一个具体应用,你是否已适应从具体应用场景到ADT的“抽象映射”?相比起P1给出了ADT非常明确的rep和方法、ADT之间的逻辑关系,P3要求你自主设计这些内容,你的感受如何?
尽量适应。无中生有有些难,不过按模板撰写就好很多。
- 为ADT撰写specification, invariants, RI, AF,时刻注意ADT是否有rep exposure,这些工作的意义是什么?你是否愿意在以后编程中坚持这么做?
这么做的意义在于为开发者提供了一系列保证保障程序可用性、可靠性、安全性的准则,保障软件质量,提升开发效率。我尽量这么做。
- 关于本实验的工作量、难度、deadline。
比较适当,但如果ddl能避开考试复习阶段就好了。
- 《软件构造》课程进展到目前,你对该课程有何体会和建议?
主要靠自学。