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 实验环境配置
GitHub Lab2仓库的URL地址:https://github.com/ComputerScienceHIT/HIT-Lab2-2021113444.git
同第一次的实验配置,由于选用IDEA作为IDE,所以统计测试用例覆盖率的插件选用IDEA自带的。
3 实验过程
请仔细对照实验手册,针对三个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。
3.1 Poetic Walks
本实验给了一个Graph接口,要设计边图和点图继承该接口,实现加权有向图,再设置为泛型。此ADT为了完成poet。考察ADT及其规约的设计,以及Junit test的编写。
3.1.1 Get the code and prepare Git repository
如何从GitHub获取该任务的代码、在本地创建git仓库、使用git管理本地开发。
3.1.2 Problem 1: Test Graph
静态测试并不复杂,根据Graph提供的规约测试即可。
对于graphInstance来说,按照ADT的规约去测试它,尽量做到情况的全覆盖。
而后应用IDEA自带的测试覆盖率运行。
3.1.3 Problem 2: Implement Graph
重写Graph里的方法,分别完成以点为基础的图和以边为基础的图。
3.1.3.1 Implement ConcreteEdgesGraph
以边为基础的对于接口的实现,包含以下两部分:
EDGE:
Source:边的起始点。
Target:边的终止点。
Weight:边的权重。
Edge:边本身,初始化上述三个成员变量。
Checkrep:检查边权是否是正整数,始末点是否不同且不为空。
SameEdge:判断是否出现相同的边。
ToString:输出边的相关信息,方便测试和调试。
ConcreteEdgesGraph:
Setvertices:图的顶点集。
List<Edge>edges:图的边列表。
Add:增加点。
Set:增加边、删除边或修改边,按照是否存在边和给予的权重来判断。
使用SameEdge来判断边是否相等。
Remove:删除点,并删除依赖的边,先检查点是否在点集合里,而后遍历寻找相关的边。
Vertices:返回vertices。
Sources:返回起点集合。
targets:返回终点集合。
toString:以字符串形式输出图的信息。
Setvertices:点集。
List<Edge>edges:边集。
CheckRep:检查edge必须有起始点、终止点和权重。同一起始点和终止点中只能有一条edge。所有顶点必须在vertices里。
测试结果:
3.1.3.2 Implement ConcreteVerticesGraph
以点为基础实现,包含以下两个部分:
Vertex:
label:点的标签。
Map<L,Integer> sources:点的前点的映射,包含权重。
Map<L,Integer> targets:点的后点的映射,包含权重。
Vertex:初始化标识。
CheckRep:检查标签不为空,检查权值大于0,检查source和target不为null 且不同于顶点。
sameVertex:检查顶点是否相同。
getLabel:获取顶点标签。
addSource:为顶点添加前点和权重。
addTarget:为顶点添加后点和权重。
removeSource:移除顶点的前点,先检查点是否存在。
removeTarget:移除顶点的后点,先检查点是否存在。
resetSource:重设顶点的前点的权重。
resetTarget:重设顶点的后点的权重。
toString:同上
Concreteverticesgraph:
List<vertex>vertices:顶点集
Checkrep:不能有空节点
verticeContains:检查顶点集中是否含有该标签
add:顶点集增加一个顶点(检查是否含有相同顶点)
set:增加边,根据权重和是否含有该边来判断是增加边、修改边还是移除边。添加边时要注意边的两个顶点都要修改。
remove:移除顶点,之后遍历其他顶点,删除相关的边。
vertices:返回顶点集。
sources:返回顶点的前点集,调用getSources即可。
targets:返回顶点的后点集,调用getTargets即可。
toString:同上。
测试结果:
3.1.4 Problem 3: Implement generic Graph
3.1.4.1 Make the implementations generic
将String改为泛型L即可。
3.1.4.2 Implement Graph.empty()
用ConcreteEdgeGraph实现Graph.empty()方法。
3.1.5 Problem 4: Poetic walks
3.1.5.1 Test GraphPoet
按照要求覆盖多种可能性即可,有bridg,无bridge,两词存在,一词存在,无词存在。
3.1.5.2 Implement GraphPoet
用Graph实现GraphPoet,分为两个部分:
GraphPoet:
使用bufferedReader按行读取文件内容,之后使用split方法进行分割,存于数组之中,并且转换为小写。然后两个两个的存于graph。
checkRep:
检查是否有野点,即无头无尾的点。
poem:
将输入的字符串用split分割,每两个词一组,取前词的后点集合和后词的前点集合,使用retain方法求交集即bridge,而后进行排序,找到权值最大的bridge,加入答案字符串。
测试结果:
3.1.5.3 Graph poetry slam
略
3.1.6 使用Eclemma检查测试的代码覆盖度
测试代码覆盖率均为100%。
3.1.7 Before you’re done
请按照http://web.mit.edu/6.031/www/sp17/psets/ps2/#before_youre_done的说明,检查你的程序。
如何通过Git提交当前版本到GitHub上你的Lab2仓库。
在这里给出你的项目的目录结构树状示意图。
3.2 Re-implement the Social Network in Lab1
3.2.1 FriendshipGraph类
(1)设计思路
继承ConcreteEdgesGraph,并在类中增加一些对非法情况的判断,例如顶点已经存在,边已经存在或找不到对应顶点等。
(2)方法实现
① public boolean addVertex(Person people)
这个函数是为把参数添加到图中,作为图的一个顶点,直接调用add()即可。调用过程中检查顶点中是否已出现参数对应的顶点,若重复则返回false,成功添加顶点则返回true
② public boolean addEdge(Person s, Person e)
构建图的要素,在图中添加边。先调用vertices().contains()方法来判断所添加边的顶点是否存在,若条件满足,则调用this.set()方法设置边,权重初始化为1并返回true,其余情况返回false。
③ public int getDistance(Person s, Person e)
获取两个顶点之间距离的函数,题目要求返回最短距离,因此采用广度遍历的方式,此处需要用到Queue的数据结构,并且设置了一个List来存放已经访问过的person。
3.2.2 Person类
Person类的姓名应该为私有变量,并且构造时要判断是否重名。
设置私有变量,构造函数访问FriendshipGraph类的静态列表,检查是否重名,重名则报错退出;不重名则更新静态列表。设置公开函数getter访问Person的姓名。
能成功储存人物姓名,并且能在重名情况下报错退出。
3.2.3 客户端main()
根据样例进行设计。
3.2.4 测试用例
各测试样例要能检测各变量是否在正确状态。
addVertex函数中测试添加节点的人物是否成功添加到映射里。
addEdge函数中测试邻接矩阵中相应的位置的距离数值是否正确设置。
getDistence函数中测试是否返回正确的距离值。
3.2.5 提交至Git仓库
IDEA直接使用git提交并推送。
目录结构树状示意图: