软件构造LAB2的一些思考

1.实验目标概述

本次实验训练抽象数据类型(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 并据此设计测试用例。

2.实验环境配置

本实验需要用到Eclipse中的EclEmma来测试测试文件的覆盖度,我们可以直接在Eclipse中搜索安装。

本次实验给出了一个抽象的图接口,要求我们用边和点两种方法来继承实现这个抽象接口,并且在子类里面实现一系列方法。之后用这个图的抽象数据型完成poet的工作。主要考察ADT的规约设计和ADT的实现。

3.实验过程

3.1Problem 1: Test Graph <String>

本问题针对Graph<String>设计相应的测试策略,主要针对里面的每个方法进行等价类划分的测试。

Testing strategy:

(1)对于add方法,我们使用空图加点和重复加点两种方式测试。

(2)对于set方法,我们使用空集加权重为0的边和空集加权重不为0的边,非空集有未相连两点加权重不为0的边和加权重为0的边,非空集有相连的两点加权重为0和不为0的边进行测试。

(3)对于remove方法,我们可以对移除已存在点和未存在点两种情况测试,同时测试移除点之后的源点集判断是否成功去掉边。

(4)测试vertices方法,使用空图和非空图测试。

    (5)测试返回源点集,使用空源点和有源点两种测试。

(6)测试返回目标点集,使用空目标点和有目标点两种测试。

3.2Problem 2: Implement Graph <String>

3.2.1 ConcreteEdgesGraph

实现Edge类

(1)类中的字段应该包括边的长度,边的起点和终点,并且定义为私有类型。这些变量如下图:

(2)类中需要实现的方法如下图所示:

Edge

初始化构造方法,初始化新边的两个点和边的权值

checkRep

检查表示不变性,边不为空且权值大于0

getsource

返回边的一个点的源点

gettarget

返回边的另外点的目标点

getweight

返回边的权重

toString

返回一条边的字符串,形式为“起点->终点 权重:xx”

(3)AF,RI和Safety from rep exposure如下图:

(4)测试策略:

实现ConcreteEdgesGraph类

(1)类的字段中应该包括顶点set表和边list表,定义私有类型的表如下图所示:

(2)在ConcreteEdgesGraph中需要实现的方法如下图所示:

checkRep

检查表示不变性,类中边的权重必须大于0

add

顶点集中没有该点时,添加该顶点进入点表中

set

输入source,target,weight,分别为边的起点、终点和权值。若权值为正且边已经存在,则修改边的权值。若权值为正且边不存在,则直接添加新边。若权值为0且边已经存在,则删去原边。若权值小于0,则返回0。只要改变了原边权值,都返回原边权值,没有权值则返回0

remove

除去某个点及与它相邻的所有边。只需要遍历edges,寻找是否有边的起点或者终点为该点,直接删去即可

vertices

返回所有的点集

sources

输入一个终点,返回与它相连的所有边和起点构成的Map

targets

输入一个起点,返回与它相连的所有边和终点构成的Map

toString

调用Edge类中的toString方法将整个图中所有点的指向转化为一条字符串输出

(3)AF,RI和Safety from rep exposure如下图:

(4)测试策略:

该测试已经继承Graph的测试策略,所以只需要增加toString的测试和对Edge类的测试即可:

测试tostring:使用空图和非空图返回判断字符串是否相等进行测试。

测试Edge集:使用加点后判断返回的source,target,weight是否相等测试。

测试ConcreteEdgesGraphTest.java

3.2 ConcreteVerticesGraph

设计Vertex类

(1)类中的字段应该包括点的名字和以该点为源点的目标点集,并且定义为私有类型。这些变量如下图:

(2)类中需要实现的方法如下图所示:

checkRep

检查表示不变性,每个边的权值应该大于0

getname

返回点的名字name

getsource

返回该点能到达的所有点和边权值构成的Map

getweight

输入一个目标点,返回该点到目标点的边的权值

remove

输入一个目标点,若该点的目标点集中有该点则删去,否则返回false

change

输入一个目标点和权重,类似于set

toString

得到以该点为源点的包含所有它的目标点的字符串表示

Vertex

初始化构造方法,用点的名字创建

(3)AF,RI和Safety from rep exposure如下图:

(4)该测试已经继承Graph的测试策略,所以只需要增加toString的测试和对Vertex类的测试即可:

测试tostring:使用空图和非空图返回判断字符串是否相等进行测试。

测试Vertex集:使用加点后判断未修改就返回的目标点集,和对点的边进行修改后返回的目标点集进行测试。

测试ConcreteVerticesGraphTest.java

3.3 Implement generic Graph<L>

要求我们使用泛型修改之前编写的String:将之前我们使用String实例的地方全部改为L,可借助Eclipse的报错辅助修改:

Implement Graph.empty()

需要在Graph类接口empty方法中返回一个具体的实现:

测试结果:

测试覆盖率为:

3.4Problem 4: Poetic walks

该问题要求我们实现一个类,必须利用之前实现的图结构,将一个文件输入的语料库转化为图结构,对输入的句子在图中搜索节点,完成扩充。

​​​​​​​Test GraphPoet

测试结果:

测试覆盖率为:

​​​​​​​Implement GraphPoet

(1)GraphPoet的字段为String构成的Graph,定义私有类型的表如下图所示:

(2). AF,RI和Safety from rep exposure如下图:

(3).在GraphPoet中需要实现的方法如下图所示:

GraphPoet

输入文件的路径,按行读取,按照空格划分为一个个元素,之后将这些元素加入图作为点,然后每次取相邻的元素,在图中添加边。

checkRep

检查不变性,必须保存从语料库文件生成的图

poem

输入字符串,使用一个StringBuilder保存我们扩充后的字符串,每次读取一个词,加入StringBuilder,然后以该词作为source,下一个词作为target,然后在Garph中寻找source的终点表中是否有与target的源点表中相同的元素,之后比较权值大小找到权值最大的和的点加入StringBuilder中,待到完成搜索,返回扩充后的字符串

toString

调用ConcreteEdgesGraph中的toString方法,将整个图中所有点的指向转化为一条字符串输出

​​​​​​​Graph poetry slam

我们在输出返回的扩充的边之后再返回语料库生成的图:

​​​​​​​使用Eclemma检查测试的代码覆盖度

测试结果:

测试覆盖率为:

​​​​​​​​​​​​​​​​​​​​​

Social Network

我们在LAB1中使用Person类作为点,设计了很多方法来完成存储点集,存储边集,完成点的加入,边的加入,以及求取点的连接的边。在本次实验中,我们已经完成了图结构的编写,所以可以直接用图结构中的方法完成要求,例如:直接使用Graph<L>作为图结构,我在项目中使用的是ConcreteEdgesGraph<L>的实现。使用add完成添加点,set完成添加边,sources和targets可以获取点与边的关系,vertices可以获取点集。

​​​​​​​FriendshipGraph

(1)该类中的字段为以Person为点类型的图Graph:

(2)类中的AF,RI和Safety from rep exposure如下图:

(3)在FriendshipGraph需要实现的方法如下图所示:

FriendshipGraph

构造方法

addVertex

在图中增加新Person,调用ConcreteEdgesGraph中的add即可

addEdge

输入两点加入他们之间的边,直接调用ConcreteEdgesGraph中的set即可:

getDistance

得到两个人之间的最短距离。与Lab1类似,我们首先使用一个Map<Person, Integer>visited表示每个点的状态,0为未搜索,1为已搜索,再将第一个点入队,改变状态开始广度优先搜索,我们对于每个点调用他们的targets方法获取他们的目标节点集,然后入队,改变他们距离第一个节点的距离,直到我们找到第二个节点,直接返回我们存储再distance中的距离值即可。

main

与LAB1一致

​​​​​​​Person

(1)类中的字段包括点的名字:

private final String name;

(2)Person类只是作为一个点的存在,它相当于L,不需要有其他太多功能。其方法为:

Person

输入名字,构造方法

getname

返回本人名字,直接返回即可

(3)类中的AF,RI和Safety from rep exposure如下图:

运行结果:

​​​​​​​​​​​​​​测试用例

与LAB1思路一致,但更简洁:

测试结果如下:

测试用例覆盖度:

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值