根据实验手册简要撰写。本次实验训练抽象数据类型(ADT)的设计、规约、测试,并使用面向对象
编程(OOP)技术实现 ADT。具体来说:针对给定的应用问题,从问题描述中识别所需的 ADT:设计 ADT 规约(pre-condition、post-condition)并评估规约的质量; 根据 ADT 的规约设计测试用例;ADT 的泛型化;根据规约设计 ADT 的多种不同的实现;针对每种实现,设计其表示(representation)、表示不变性(rep invariant)、抽象过程(abstractionfunction)使用 OOP 实现 ADT,并判定表示不变性是否违反、各实现是否存在表示泄露(rep exposure);测试 ADT 的实现并评估测试的覆盖度;使用 ADT 及其实现,为应用问题开发程序;
在测试代码中,能够写出 testing strategy
此次实验环境配置有了第一次实验的经验变得得心应手起来:
- 首先从github上clone到本地仓库
- 在本地仓库中建立项目,并将项目文件全部添加到本地仓库中
- 进行代码提交,将本地仓库的代码推送到远程仓库。
这项任务主要是为了让我们熟悉ADT的设计,以及如何通过不同的类实现同一个ADT,在这个过程中,用户并不清楚具体的实现方式,而是通过统一的方法去实现自己的程序。同时,这个实验还让我们练习了AF,RI,以及如何防止表示泄露让我们将所学的内容应用于实践
Get the code and prepare Git repository
- 在命令行输入git clone+地址,克隆到本地仓库。
- 将项目建立到这个文件夹中
- 使用git add,git commit等命令提交至本地仓库
- 使用git push origin main命令推送到远程仓库。
Problem 1: Test Graph <String>
以下各部分,请按照MIT页面上相应部分的要求,逐项列出你的设计和实现思路/过程/结果。
这个部分是对测试优先代码设计的实践,我们站在client的角度对代码进行黑盒测试:
对add测试:/*Testing strategy
*这是一个mutator方法,调用observe来观察
*按输入点的类型划分:输入的点已经在图中,输入的点不在图中
*覆盖每个取值如下:
*/
对set测试:
/*Testing strategy
*This is a mutator function
* so we use observor to observe it
* 输入按边的类型进行划分:边的两个顶点都在图中(weight>0,weight=0);边的一个顶点在图中,另一个不在;边的两个顶点都不在图中
*/
对remove测试:
/*Testing strategy
*this is a mutator function,so we use observe to observe it
* 按顶点的类型进行划分:在图中or不在图中
*/
对vertices测试:
/*Testing strategy
*this is a observe,so we use mutator change the value in it to test it
* 按顶点的类型进行划分:已经在图中的顶点与还不在图中的顶点。
*/
对sources测试;
/*Testing strategy
*this is a observor,so we use mutator change the value in it to test it
* 按顶点的类型进行划分:已经在图中的顶点与还不在图中的顶点。
*/
对target测试:
/*Testing strategy
*this is a observor,so we use mutator change the value in it to test it
* 按顶点的类型进行划分:已经在图中的顶点与还不在图中的顶点。
*/
Problem 2: Implement Graph <String>
Implement ConcreteEdgesGraph
首先这个图是边图,其中有两个集合,一个是顶点集,一个是边集,我们首先需要设计边这个结构:
边需要有起点,终点和边上的权重。
其方法都是为了得到这些属性。
然后我们去一一实现接口中的方法:
add方法非常简单,只需要向vertices集合中添加顶点即可。
Set方法有难度,根据要求,我们先将边分为大于零等于0两类,然后将顶点分为在顶点集中与不在顶点集中两类,然后我们分情况依次完成即可:
Remove方法要求我们除去和顶点相关联的边,这就需要我们遍历edge列表去删除对应的边,具体实现如下:
而sources与target方法实现思路类似,都是遍历边集然后将顶点和边的权重添加到map中,具体实现如下:
Implement ConcreteVerticesGraph
这个类是顶点图,其主要属性为每个图的顶点,即由顶点构成这个图:
对其属性设置如下,顶点的名字,指向他的顶点集合以及他所指向的顶点集。
我实现了以下方法,方便对整个类的实现:增加,删除一个顶点的源点与目标点。
这里同样需要对输入的边的值进行划分,因为到这一步顶点已经存在了,所以此处不需要对顶点在不在顶点集合中进行讨论。下面我们对接口的方法进行实现:首先是add方法,因为这个方法比较容易,直接判断顶点在不在集合中后加入即可,所以此处不再赘述。
Set方法实现:我们通过调用vertex中实现的添加源点以及添加目标点的方法去实现它。
Remove方法,我们通过遍历整个顶点集合,如果顶点名称等于要删除的顶点,我们就把他直接从顶点集合中删除,如果顶点名称不等于要删除的顶点,那么我们将其从他的source以及target中删除。Vertices方法返回顶点的集合,所以我们遍历顶点集即可得到答案:
最后sources与target方法,我们直接调用目标点的sources与target方法即可。
Problem 3: Implement generic Graph<L>
Make the implementations generic
在这一步中,我们只需要将我们前面实现的类中每个String替换为泛型L即可,同时也要将vertex与edge换成泛型类。
Implement Graph.empty()
这个方法是接口中的静态方法,类似于工厂方法,我们只需要返回一个具体实现即可。我选择了边图实现。
Test GraphPoet
通过等价类划分,将输入的文件分为空文件,有一行的文件,有多行的文件,同时,将边的权重分为权值全为一与不全为1等情况,进行测试。
Implement GraphPoet
这个由于我们已经实现了两个图类,所以就变得相对简单,我们只需要先把读入的行通过split函数分为各个单词,然后调用target与sources函数得到终点与起点之间的点,从中选出重合且权值最大的即可。
如何通过Git提交当前版本到GitHub上你的Lab2仓库。
Git push origin main 命令
Re-implement the Social Network in Lab1
这个任务主要是为了让我们使用此次设计的图结构,重新完成lab1的实验,体会面向对象的真谛。
这个类的成员变量(属性)主要是我们之前完成的泛型类,其中泛型以我们自己设计的person类代替。
通过set方法实现addVertex方法,通过set方法实现addEdge方法,在getDistance方法中,通过使用广度优先遍历进行执行。注意这里与lab1不同之处在于Map flag不仅记录图中的点是否经过遍历,同时也记录该点到起始点之间的最短距离。:
Person类由两个属性构成,一个String类型自己的名字,一个朋友的列表。与lab1并无什么区别。
客户端main()
使用mit在lab1中提供的代码进行实现: