补发lab2实验报告,本次实验遇到了蛮多困难,解决得也不是特别好。
本次实验训练抽象数据类型(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
环境配置与Lab1相仿。此外,本次实验在 Eclipse IDE中安装配置 EclEmma(一个用于统计JUnit测试用例的代码覆盖度测试用例的代码覆盖度plugin)
在这里给出你的GitHub Lab2仓库的URL地址(Lab2-学号)
请仔细对照实验手册,针对三个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。
分别建立两个类ConcreteEdgesGraph,ConcreteVerticesGraph 实现Graph接口。Graph接口要求实现add(添加新节点),set(添加新边),remove(移除节点),vertices(获得所有的节点集合),sources(target)获得以target为目标节点的边的起始节点,targes(source)获得以source为起始节点的边的目标节点。还要求将ADT泛型化。并且编写测试文件的时候,需要从实现的基本功能出发,有良好的测试覆盖率。
如何从GitHub获取该任务的代码、在本地创建git仓库、使用git管理本地开发。
获取代码:访问Spring2021_HITCS_SC_Lab2/P1 at master rainywang/ Spring 2021_HITCS_SC_Lab2 (github.com)下载P1文件夹,获取任务代码。
git init 初始化仓库
touch.gitignore 创建ignore 文件,并且后面编辑该文件
git add. 将当前目录暂存
git commit -m “idea init”
git remote add origin
git push origin master --force 强制覆盖远程分支
之后下载数据文件和已提供的代码,对应好目录之后再次提交推送
将Graph empty()方法修改为
public static String Graph empty() {
return new ConcreteEdgesGraph<>();
}
1.Edge类:
// Abstraction function:
// String source, target;
// int weight;
// Representation invariant:
// source, target != null;
// source != target;
// weight >= 0;
其中source、target为不可变变量,使用防御式编程,故只提供gatter方法。而weight为可变变量,提供changeWeight方法来修改其值。
另外,实现构造函数及checkRep、toString方法。
2.ConcreteEdgesGraph类
private final Setvertices = new HashSet<>();
private final List> edges = new ArrayList<>();
// Abstraction function:
// 顶点集vertices;边集edges
// Representation invariant:
// number of vertices >= 1;
// number of edges >= 0;
// 两点间最多一条边
// Safety from rep exposure:
// use private final
具体方法:
1.add(L vertex):返回set中的add方法,即如果里面有相同点则返回false。
2.set(L source, L target, int weight):先判断vertices中是否有source和target,若没有,则加上(直接调用add方法即可实现)。然后遍历edges,寻找source到target的边,若找到,就更新此时的权值,并返回原先的值。遍历后判断若新输入的weight>0,则把set的参数制成的新边加入edges,否则删除原来的边。
3.remove(L vertex):若vertices中没有该点,直接返回false;若有,遍历edges,把与之相关的边全部删除,最后把vertices中该点删除。
4.Set vertices():返回vertices。
5.Map sources(L target):在edges中寻找所有目标点是target的初始节点(加权),逐一写入新的map中,返回最终对应键值对。
6.Map targets(L source):在edges中寻找所有目标点是source的初始节点(加权),逐一写入新的map中,返回最终对应键值对。
1.Vertex类
private final L name;
private Mapsources = new HashMap();
private Maptargets = new HashMap();
// Abstraction function:
// 用vertices抽象的图,到图结构的映射
// Representation invariant:
// 不能重复、不为空
// Safety from rep exposure:
// private final
// defensive copy
提供三个setter、getter方法,方便后续更改及调用。另外,实现构造函数及checkRep、toString方法。
2.ConcreteVertices类
private final List> vertices = new ArrayList<>();
// Abstraction function:
// 用vertices点的集合抽象图的结构
// Representation invariant:
// 不重复
// Safety from rep exposure:
// private final
// defensive copy
1.add(L vertex):先寻找vertices中的name有没有与vertex中相同,若没有返回false,若有将以vertex为name的新边加到vertices中,返回true
2.set(L source, L target, int weight):先判断vertices中是否有source和target,若没有,则加上;然后遍历vertices,寻找source和target点,若找到,就通过setTarget和setSource传入weight进行处理,返回两个函数的返回值
3.remove(L vertex):遍历vertices,将其中map的键中的vertex删除,若有vertices中name是vertex,将其删除,并返回true;若没有,返回false
4.Set vertices():遍历vertices,把每个name加到set中,最后返回set
5.Map sources(L target):遍历vertices,寻找name是target的点,通过 getSource返回他的map
6.Map targets(L source):遍历vertices,寻找name是source的点,通过 getTarget返回他的map
将具体类的声明更改为:
public class ConcreteEdgesGraph implements Graph { … }
class Edge { … }
public class ConcreteVerticesGraph implements Graph { … }
class Vertex { … }
使用占位符L代替,更新两个实现以支持任何类型的顶点标签String。粗略地说,您应该能够使用!查找和替换String代码中的所有实例L。这种重构将Concrete¬EdgesGraph,Concrete¬VerticesGraph,Edge,和Vertex泛型类型。
将Graph empty()方法修改为
public static Graph empty() {
return new ConcreteEdgesGraph<>();
//throw new RuntimeException("not implemented");
}
这里以ConcreteEdgesGraph作为Graph默认的实例类,也可以用ConcreteVerticesGraph,二者是等价的。
-
-
- 使用Eclemma检查测试的代码覆盖度
-
请按照http://web.mit.edu/6.031/www/sp17/psets/ps2/#before_youre_done的说明,检查你的程序。
如何通过Git提交当前版本到GitHub上你的Lab2仓库。
Git add .
Git commit -m “xxx”
Git push origin master
在这里给出你的项目的目录结构树状示意图。
给出你的设计和实现思路/过程/结果。
private final ConcreteEdgesGraphgraph = new ConcreteEdgesGraph<>();
// Abstraction function:
//有向图构成的关系图
// Representation invariant:
//图中两点只有一条边,不存在自己到自己的边
// Safety from rep exposure:
//属性采用private final标签
1.public void addVertex(Person person) throws IllegalArgumentException:利用ConcreteEdgesGraph中已写好的add方法,向关系图中添加节点,如果图中已包含该节点抛出异常提示重名。
2.public void addEdge(Person p1, Person p2):调用ConcreteEdgesGraph中set方法设置有向边
3. public int getDistance(Person p1, Person p2):获取二人距离,具体是使用队列+深度优先搜索,如果两节点名字标签形同返回0;否则:distantMap保存其他人到Person1的距离
流程:入队自己,循环(出队,将其朋友全部入队,检查是否是Person2,不是加入distantMap,设置距离,是就返回)
4. public Set persons():调用graph.vertices()返回该关系图中所有节点拷贝的集合。
由于继承了ConcreteVerticesGraph,所以可以调用父类的rep和function,因此Person类就不需要过多的修饰和改动。
-
-
- 客户端main()
-
给出你的设计和实现思路/过程/结果。
按照Lab1实验手册实现如下程序:
public static void main(String[] args) {
FriendshipGraphgraph = new FriendshipGraph<>();
Person rachel = new Person("Rachel");
Person ross = new Person("Ross");
Person ben = new Person("Ben");
Person kramer = new Person("Kramer");
graph.addVertex(rachel);
graph.addVertex(ross);
graph.addVertex(ben);
graph.addVertex(kramer);
graph.addEdge(rachel, ross);
graph.addEdge(ross, rachel);
graph.addEdge(ross, ben);
graph.addEdge(ben, ross);
System.out.println(graph.getDistance(rachel, ross));
//should print 1
System.out.println(graph.getDistance(rachel, ben));
//should print 2
System.out.println(graph.getDistance(rachel, rachel));
//should print 0
System.out.println(graph.getDistance(rachel, kramer));
//should print -1
}
输出符合预期:
给出你的设计和实现思路/过程/结果。
测试用例与Lab1相同,但是注意换成Lab2的方法实现,例如:
而不是之前利用二维数组的形式。
测试结果如下:
-
-
- 提交至Git仓库
-
如何通过Git提交当前版本到GitHub上你的Lab2仓库。
Git add .
Git commit -m “xxx”
Git push origin master
在这里给出你的项目的目录结构树状示意图。