哈工大2021软件构造Lab2实验心得总结

在这里插入图片描述
课程实验用到的代码等放假后会上传到我的github上,
https://github.com/Graham-ella

2021年春季学期 《软件构造》课程 Lab2 实验报告

姓名Liang Hao
学号xxxxxxxx
手机xxxxxxxx
邮箱3235962608@qq.com

1 实验目标概述

本次实验训练抽象数据类型(ADT)的设计、规约、测试,并使用面向对象
编程(OOP)技术实现 ADT。具体来说:
针对给定的应用问题,从问题描述中识别所需的 ADT;
设计 ADT 规约(pre-condition、post-condition)并评估规约的质量;
根据 ADT 的规约设计测试用例;
ADT 的泛型化;
根据规约设计 ADT 的多种不同的实现;针对每种实现,设计其表示(representation)、表示不变性(rep invariant)、抽象过程(abstractionfunction)
使用 OOP 实现 ADT,并判定表示不变性是否违反、各实现是否存在表
示泄露(rep exposure);
测试 ADT 的实现并评估测试的覆盖度;
使用 ADT 及其实现,为应用问题开发程序;
在测试代码中,能够写出 testing strategy 并据此设计测试用例。

2 实验环境配置

简要陈述你配置本次实验所需环境的过程,必要时可以给出屏幕截图。特别是要记录配置过程中遇到的问题和困难,以及如何解决的。

实验所需的环境在以前的学习中就已经配好。

3 实验过程

请仔细对照实验手册,针对三个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。

3.1 Poetic Walks

这个实验的主要目的是测试 ADT 的规约设计和 ADT 的多种不同的实现,并练习 TDD 测试优先编程的编程习,在后面练习 ADT 的泛型化。

3.1.1 Get the code and prepare Git repository

从下图处获取所需代码,创建新的项目后按照要求建立目录。
在这里插入图片描述
git init初始化Git仓库,将已有的文件提交到本地仓库中,配置好远程仓库后,将本地仓库的内容push到远程仓库中。
在这里插入图片描述
在这里插入图片描述

3.1.2 Problem 1: Test Graph

设计测试Instance方法的testing strategy。主要对每一个需要测试的函数进行输入空间的划分,然后根据输入空间的划分以“最少一次覆盖”的策略进行测试。设计如下:

//boolean add(L vertex)
test add方法: 
graph:  1、graph为空
		2、graph非空
参数L vertex:  	1、新的节点
				2、已经存在graph中的点
					
//int set(L source,L target,int weight)
test set方法:
	graph:  1、graph为空
			2、graph非空
	参数L source:   1、source是新的节点
					2、source已经在graph中
	参数L target:   1、source是新的节点
					2、source已经在graph中
	参数int weight: 1、weight = 0
					2、weight > 0
					
//boolean remove(L vertex)
test remove方法:
	参数L vertex:   1、vertex为新的节点
					2、vertex已经在graph中,但没有节点和它相连
					3、vertex已经在graph中,且有节点和它相连
//Set<L> vertices()
test vertices方法:
graph:  1、graph是空图
            2、graph非空

//Map<L,Integer> sources(L target)
test sources方法:
	graph:  1、graph为空
			2、graph非空
	参数L target:   1、target是新的节点
					2、target是graph中的节点,但是没有边指向它
					3、target是graph中的节点,有边指向它
					
//Map<L,Integer> targets(L source)
test targets方法:
	graph:  1、graph为空
			2、graph非空
	参数L source:   1、source是新的节点
					2、source是graph中的点,但是没有边以它为起点
					3、source是graph中的点,且有边以它为起点

3.1.3 Problem 2: Implement Graph

以下各部分,请按照MIT页面上相应部分的要求,逐项列出你的设计和实现思路/过程/结果。
这一部分主要是将 Graph实现两次,分别基于边为主和点为主来实现图的存储和基本操作。

3.1.3.1 Implement ConcreteEdgesGraph
1)edge类的设计
edge类的成员变量如下图所示:
在这里插入图片描述
方法如下:

Edge含参构造函数,利用传入的参数创建一条新的边
checkRep检查不变量,边的权值>0,边的源顶点和目标顶点非空
getSource返回边的源顶点
getTarget返回边的目标顶点
getWeight返回边的权值
toString按照指定格式打印边,比如”a->b 权值为:1”

对于Abstraction function:
由source,target,weight组成的抽象数据型表示从源顶点到目标顶点具有权重的有向边
在这里插入图片描述
对于Representation invariant:
weight > 0 source和target不为空
在这里插入图片描述
对于Safety from rep exposure:
变量都由private和final关键字修饰,类中并没有定义set方法,成员变量都不能从类外部获取或者赋值,保证了数组不会外泄。
在这里插入图片描述
2)Testing strategy for Edge
在这里插入图片描述
3)实现Edge类和Edge类的测试
截取部分的代码如下:
在这里插入图片描述
在这里插入图片描述
4)ConcreteEdgesGraph类的设计
成员变量和成员函数如图所示:
在这里插入图片描述
对于Abstraction function:
vertices 表示图中的点 edges 表示图中的边,AF是从这两种抽象数据类型到一个对应有向图的映射
在这里插入图片描述
对于Representation invariant:
顶点不能为空,边的权值要大于0
在这里插入图片描述
对于Safety from rep exposure:
vertices和 edges都用private和final关键字修饰,返回时利用防御性拷贝
在这里插入图片描述
5)实现ConcreteEdgesGraph类和它的测试
截取部分的代码如下:
在这里插入图片描述
6)运行测试
全部通过
在这里插入图片描述
覆盖率测试如下图所示,覆盖率高达100% :
在这里插入图片描述
3.1.3.2 Implement ConcreteVerticesGraph
1)Vertex类的设计
Vertex类的成员变量如图所示:
在这里插入图片描述
Vertex类的成员函数包括:

Vertex含参构造函数,public Vertex(final String name)
Vertex含参构造函数,public Vertex(final String name, final Map<String,Integer> connec)
checkRep检查不变量,顶点的name不为空或者””,边的权值>0
getName获取顶点名称
getConnec获取顶点的边集
remove删除这个源点的某条边
put加边或者修改权值
getWeight获取指定边的权值
toString按指定格式打印

类的UML图如下图所示:
在这里插入图片描述
对于Abstraction function:
代表有权值的有向边中的源点
在这里插入图片描述

对于Representation invariant:
顶点名不为空或者””,边的权值大于0
在这里插入图片描述

对于Safety from rep exposure:
name和connec都用private, final关键字修饰,函数返回时创建一个新的对象
在这里插入图片描述
2)Testing strategy for Vertex
在这里插入图片描述
3)实现Vertex类和它的测试
部分代码如图所示:
在这里插入图片描述
4)ConcreteVerticesGraph类的设计
UML图如下:
在这里插入图片描述
对于Abstraction function:
vertices到有向图的映射
在这里插入图片描述
对于Representation invariant:
vertices之间不能重复 每个顶点的名字不为空 每条边的权值大于0
在这里插入图片描述
对于Safety from rep exposure:
vertices用private,final关键字修饰,返回时用防御性拷贝
在这里插入图片描述
4)实现ConcreteVerticesGraph类和它的测试
部分代码截图如下:
在这里插入图片描述
在这里插入图片描述
5)运行测试
测试全部通过
在这里插入图片描述
代码覆盖率高达100%
在这里插入图片描述

3.1.4 Problem 3: Implement generic Graph

将已有的两个 Graph的实现改为Graph的泛型实现。

3.1.4.1 Make the implementations generic
将ConcreteEdgesGraph和ConcreteVerticesGraph都用泛型实现后,重新跑测试
在这里插入图片描述
在这里插入图片描述
覆盖率依旧是100%
在这里插入图片描述
3.1.4.2 Implement Graph.empty()
1、选择ConcreteEdgesGraph 作为返回对象实现Graph.empty()函数:
在这里插入图片描述
2、测试GraphStaticTest
尝试label为long的情况:
在这里插入图片描述
尝试label为double的情况:
在这里插入图片描述
写完后运行测试,运行成功
在这里插入图片描述
查看一下覆盖率,依旧是100%:
在这里插入图片描述

3.1.5 Problem 4: Poetic walks

这个问题一部分是用给的语料生成图,相邻的单词间用一条有向边连接,另一部分是给定一个输入字符串,通过在图中判断它们之间是否有bridge来对字符串进行扩充。

3.1.5.1 Test GraphPoet

Testing strategy:
    对于构造函数:
1、传入不存在的文件 
2、传入的文件为空
3、传入的语料文件只有一行单词 
4、传入具有多行的语料文件

    对于poem函数:
1、传入的字符串为null 
2、传入的字符串!=null,但只有一个单词 
    3、传入的字符串!=null,不止一个单词(还可以再设计根据权值选bridge的情形)

    对于toString函数:
1、graph为空 
2、graph不为空,但没有边 
3、graph有顶点有边

测试策略部分截图如下:
在这里插入图片描述
3.1.5.2 Implement GraphPoet
1)GraphPoet的结构分析
UML图如下:
在这里插入图片描述
对于成员变量graph:
在这里插入图片描述
对于含参构造函数:
1、如果传入的文件不存在,catch异常,打印
在这里插入图片描述
2、如果文件存在,按行读入,根据要求生成对应的图
在这里插入图片描述
对于poem方法:
关键在于寻找bridge,当有多个符合要求的节点时,要选择权值大的。
在这里插入图片描述
对于toString方法:
沿用ConcreteEdgesGraph.java中的打印方法

2)关于AF,RI和rep exposure

对于Abstraction function:
将文本文件转化成有向图,图的顶点就是文件中的单词,相邻单词在图中对应的顶点间有有向边
在这里插入图片描述
对于Representation invariant:
图中的顶点不为空或者"",边的权值要大于0
在这里插入图片描述
对于Safety from rep exposure:
graph用private和final关键字修饰,返回参数时创建新的变量
在这里插入图片描述
3)类的实现
部分代码截图如下:
在这里插入图片描述
4)测试

对poem参数不同情况下的测试:
当传入的文件不存在时,控制台打印“传入的语料文件不存在!”
在这里插入图片描述
当传入的语料库文件为空时,poem后的字符串和以前一样
在这里插入图片描述
下面是语料库有一行或多行字符串时的情况
在这里插入图片描述
对ToString在空图、图非空(只有顶点)、图非空(既有顶点,也有边)的情况下的测试:
在这里插入图片描述
对bridge按照权值大小选取的测试:
如下图所示,构造一个特殊的图,涉及到bridge的选择
在这里插入图片描述
在这里插入图片描述
所有的测试结果:
在这里插入图片描述
覆盖率测试如下:
在这里插入图片描述
3.1.5.3 Graph poetry slam

选取了WILLIAM BUTLER YEATS 的When You Are Old
输入字符串为”you old”,扩充后的结果为”you are old”
在这里插入图片描述

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仓库。
在这里插入图片描述
直接通过idea来提交会更加方便

项目的目录结构树状示意图如下:
在这里插入图片描述

3.2 Re-implement the Social Network in Lab1

这个任务主要是重新实现 Lab1 中的 Social Network,利用在P1中已经写好的 Graph接口来实现,尽量重用已有的函数。

3.2.1 FriendshipGraph类

这里给出FriendshipGraph类的UML图
在这里插入图片描述
包含成员变量Vertex:
在这里插入图片描述
用来保存图中的各顶点。

对于addVertex方法:
充分使用 Graph里面提供的函数 add,即可实现增加顶点的功能。如果顶点名重复,打印错误信息,程序直接退出。

对于addEdge方法:
充分利用 Graph里面提供的函数 set,即可实现增加顶点的功能,不过要先判断两个顶点是否相同。

对于getDistance方法:
利用BFS算法来求两个顶点之间的最短距离。

3.2.2 Person类

下面给出Person类的UML图:
在这里插入图片描述
对于Abstraction function:
在这里插入图片描述
对于Representation invariant:
在这里插入图片描述
对于Safety from rep exposure:
在这里插入图片描述

3.2.3 客户端main()

利用 Lab1 中已有的 main 客户端即可。

3.2.4 测试用例

测试策略主要是根据 FriendshipGraph 中的图的类型进行测试,主要分为空图的测试、仅有顶点的图的测试、复杂图的测试。

测试结果如下图:
在这里插入图片描述
覆盖率测试如下图所示:
在这里插入图片描述

3.2.5 提交至Git仓库

如何通过Git提交当前版本到GitHub上你的Lab3仓库。
在这里插入图片描述
用idea的git工具来提交会更快。

在这里给出你的项目的目录结构树状示意图。
在这里插入图片描述

4 实验进度记录

请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。

日期时间段任务实际完成情况
xxxxxxxxxxxx
xxxxxxxxxxxx
xxxxxxxxxxxx
xxxxxxxxxxxx

5 实验过程中遇到的困难与解决途径

遇到的难点解决途径
英文题目看不懂Google翻译,逐字逐句揣摩
Java的泛型和接口概念不懂菜鸟教程自学

6 实验过程中收获的经验、教训、感想

6.1 实验过程中收获的经验和教训

代码的性能可以再优化,对于成员变量的封闭性平时考虑的比较少。

6.2 针对以下方面的感受

(1) 面向ADT的编程和直接面向应用场景编程,你体会到二者有何差异?

在面向 ADT 编程的时候更多的需要考虑代码的可复用性,需要使整个的编程更加具有普适性;而面向应用场景编程,更加直接和方便,但是适用的范围明显更小。

(2) 使用泛型和不使用泛型的编程,对你来说有何差异?

使用泛型编程的话,写起来不太习惯,而不使用泛型编程的话,写起来更加顺手。

(3) 在给出ADT的规约后就开始编写测试用例,优势是什么?你是否能够适应这种测试方式?

可以尽早发现错误,可以逐渐适应。

(4) P1设计的ADT在多个应用场景下使用,这种复用带来什么好处?

可以将已有的代码进行复用来尽量节省时间。

(5) P3要求你从0开始设计ADT并使用它们完成一个具体应用,你是否已适应从具体应用场景到ADT的“抽象映射”?相比起P1给出了ADT非常明确的rep和方法、ADT之间的逻辑关系,P3要求你自主设计这些内容,你的感受如何?

没做P3。

(6) 为ADT撰写specification, invariants, RI, AF,时刻注意ADT是否有rep exposure,这些工作的意义是什么?你是否愿意在以后编程中坚持这么做?

提前发现错误,避免数据外泄,愿意。

(7) 关于本实验的工作量、难度、deadline。

工作量比较大,时间紧凑。

(8) 《软件构造》课程进展到目前,你对该课程有何体会和建议?

和计算机系统一起同时做实验,有点累人。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值