哈工大软件工程Lab2实验心得

2022年春季学期
计算学部《软件构造》课程

Lab 2实验报告

目录

1 实验目标概述

2 实验环境配置

3 实验过程

3.1 Poetic Walks

3.1.1 Get the code and prepare Git repository

3.1.2 Problem 1: Test Graph <String>

3.1.3 Problem 2: Implement Graph <String>

3.1.3.1 Implement ConcreteEdgesGraph

3.1.3.2 Implement ConcreteVerticesGraph

3.1.4 Problem 3: Implement generic Graph<L>

3.1.4.1 Make the implementations generic

3.1.4.2 Implement Graph.empty()

3.1.5 Problem 4: Poetic walks

3.1.5.1 Test GraphPoet

3.1.5.2 Implement GraphPoet

3.1.5.3 Graph poetry slam

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

3.1.7 Before you’re done

3.2 Re-implement the Social Network in Lab1

3.2.1 FriendshipGraph类

3.2.2 Person类

3.2.3 客户端main()

3.2.4 测试用例

3.2.5 提交至Git仓库

4 实验进度记录

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

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

6.1 实验过程中收获的经验和教训(必答)

6.2 针对以下方面的感受(必答)

  1. 实验目标概述

本次实验训练抽象数据类型(ADT)的设计、规约、测试,并使用面向对象

编程(OOP)技术实现 ADT。具体来说:

l 针对给定的应用问题,从问题描述中识别所需的 ADT

l 设计 ADT 规约(pre-conditionpost-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.实验环境配置

本次实验继续使用实验一时已经配置好的环境,不需要再次配置。

IDEA中自带用于统计JUnit测试用例的代码覆盖度的plugin,不需要再安装。

GitHub Lab2仓库的URL地址:

https://github.com/ComputerScienceHIT/HIT-Lab2-2021111824.git

3.实验过程

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

3.1Poetic Walks

该任务主要为进行不同类型ADT的设计以及对ADT规约的测试,并练习进行测试优先的编程。在任务的后半部分还有对ADT的泛化。

3.1.1Get the code and prepare Git repository

(1)使用git clone指令从GitHub获取该任务的代码

 

(2)在本地创建git仓库

 

(3)使用git管理本地开发

                               与远程仓库连接

3.1.2Problem 1: Test Graph <String>

我们要对Graph接口上的方法进行测试

(1)empty方法的测试已经给出,不需再进行修改

(2)对于add、remove、set、vertices、sources、targets等方法的测试用例书写,采用以下等价类划分方法

 

测试用例全部通过

 

代码覆盖率

 3.1.3 Problem 2: Implement Graph <String>

3.1.3.1Implement ConcreteEdgesGraph

首先,我们先应实现Edge类

(1)Edge中应含有三个私有变量source、target、weight分别代表源点、目标顶点以及边的权值

 

(2)然后设计checkRep函数:源点及目标定点不为空且权值不为负 

 

(3)实现Edge的构造方法

 

(4)实现Edge的基本方法

 

(5)最后实现函数toString

 

然后,来实现ConcreteEdgesGraph类

(1)先定义顶点和边的集合

 

(2)然后设计checkRep函数:边的权值不为负且源点和目标点都在顶点集合中

 

(3)实现构造方法

 

(4)实现该类中的其他方法

 Ⅰ. add

需要遍历vertices集合,查找有无与点vertex相同的点。若存在,则返回false;若不存在,则将点vertex加入vertices集合中,返回true。

 

Ⅱ. set

该方法主要包括三种操作:修改已存在边的权值,移除已存在的边,增加新的边。

先判断weight的值,若weight小于0,则报错退出;否则,进行以下步骤:

先遍历edges集合

若该边已经存在于edges中:1)weight > 0,修改该边权值,并返回原权值;

2)weight = 0,删除该边,并返回原权值;

若该边不存在于edges中:  1)weight > 0,将该边添加到edges集合中,并将 不存在于vertices集合中的顶点添加到vertices  集合中,然后返回0;

2)weight = 0,直接返回0。

 

Ⅲ. remove

若该顶点存在于vertices中,将edges集合中所有以vertex为源点或目标点的边全部移除,然后将该顶点从顶点集合vertices中移除,并返回true;否则返回false。

 

Ⅳ. vertices

返回由图的顶点构成的集合。为了防止信息泄露,使用防御式拷贝。

 

Ⅴ. sources

返回所有以target为目标顶点的点以及对应边的权值。返回值的类型为Map,所以需要构造一个Map,然后遍历edges集合寻找所有以target为目标顶点的边并将其源点作为键名、权值作为键值添加到Map中,最后返回该Map。

 

Ⅵ. targets

返回所有以source为源点的点以及对应边的权值。返回值的类型为Map,所以需要构造一个Map,然后遍历edges集合寻找所有以source为源点的边并将其目标顶点作为键名、权值作为键值添加到Map中,最后返回该Map。

 

(5)toString

先将vertices中所有的点打印出来,然后遍历edges集合,循环调用Edge类的toString方法,将边打印出来。

 3.1.3.2 Implement ConcreteVerticesGraph

首先,我们应该先实现Vertex类

(1)Vertex的成员变量包括:顶点名称、源点集合和目标顶点集合

 

(2)给出构造方法

 

(3)设计checkRep函数:检验顶点名称不为空、不含有重复的顶点且编的权值非负

 

(4)Vertex中的其他方法

Ⅰ. get...

返回顶点名称、源点及目标定点集合(注意防御式拷贝)

 

Ⅱ.remove_source

若该点存在于源点集合中,则移除该顶点,并返回true;否则返回false。

 

Ⅲ.remove_target

若该点存在于目标顶点集合中,则移除该顶点,并返回true;否则返回false。

 

Ⅳ.add_source

该方法主要包括三种操作:修改已存在边的权值,移除已存在的边,增加新的边。

先判断weight的值,若weight小于0,则报错退出;否则,进行以下步骤:

先遍历sources中的键名

若该点已经存在于sources中: 1)weight > 0,修改该边权值,并返回原权值;

2)weight = 0,删除该边,并返回原权值;

若该点不存在于sources中:   1)weight > 0,将该点添加到sources键名中,           并将weight设置为其对应的键值,返回0;

2)weight = 0,直接返回0。

 

Ⅴ.add_target

该方法主要包括三种操作:修改已存在边的权值,移除已存在的边,增加新的边。

先判断weight的值,若weight小于0,则报错退出;否则,进行以下步骤:

先遍历targets中的键名

若该点已经存在于targets中: 1)weight > 0,修改该边权值,并返回原权值;

2)weight = 0,删除该边,并返回原权值;

若该点不存在于targets中:   1)weight > 0,将该点添加到targets键名中,           并将weight设置为其对应的键值,返回0;

2)weight = 0,直接返回0。

 

(5)toString

打印该点的信息

 

然后,我们再来实现ConcreteVerticesGraph类

(1)实现构造方法

 

(2)设计checkRep函数:判断顶点的名字不为空且不存在相同的顶点

 

(3)设计该类中其他方法

Ⅰ.add

遍历vertices集合,若存在vertex,则返回false;若不存在,则将vertex加入vertices中,并返回true。

 

Ⅱ.set

该方法主要包括三种操作:修改已存在边的权值,移除已存在的边,增加新的边。

先判断weight的值,若weight小于0,则报错退出;否则,进行以下步骤:

将source、target加入vertices集合中,然后调用Vetex类中实现的add_source与add_target方法即可。

 

Ⅲ.remove

遍历vertices集合,判断vertex是否在集合中,若存在,则调用Vertex中的remove_source与remove_target方法删除以vertex为顶点的边并将vertex从vertices集合中移除,然后返回true;否则,返回false。

 

Ⅳ.vertices

返回由图的顶点构成的集合。使用防御式拷贝,构建一个新的集合,将vertices集合中所有点的标识加入该集合中。

 

Ⅴ.sources

返回顶点target的源点集合,注意使用防御式拷贝。

 

Ⅵ.targets

返回顶点source的目标顶点集合,注意防御式拷贝。

 

(5)toString

先将所有的点的名称打印出来,随后遍历vertices集合,循环调用vertices类的toString方法。

 3.1.4 Problem 3: Implement generic Graph<L>

将原有的Graph<String>转化为泛型

3.1.4.1 Make the implementations generic

我们只需将声明中的String替换为L即可

3.1.4.2 Implement Graph.empty()

 3.1.5 Problem 4: Poetic walks

通过刚才实现的Graph类,来实现一个语句扩充问题

3.1.5.1Test GraphPoet

需要将情况划分为空文件、单行文字、多行文字进行测试

 3.1.5.2 Implement GraphPoet

该类需要实现以下功能:

(1)读入文本文件,并将其抽象为一个带权有向图:

每个单词抽象为顶点、相邻两个单词之间抽象为边,且出现一次权值为1;

(2)对目标字符串进行扩充:

遍历给定文本的单词,对于每一个单词,我们要找出该点所指向的目标顶点集中权值最大的元素,将其添加在原来的两个单词之间。遍历结束后,返回扩充后的字符串。

3.1.5.3 Graph poetry slam

这里实现了自己添加的一个例子,成功将字符串扩充

 

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

 

 

代码覆盖率较高,方法都已基本实现

3.1.7 Before you’re done

如何通过Git提交当前版本到GitHub上你的Lab2仓库。

使用git add添加文件

     git commit提交到本地

   git push推送到GitHub

在这里给出你的项目的目录结构树状示意图。

 3.2 Re-implement the Social Network in Lab1

我们需要利用在P1中设计的Graph类来实现第一次实验中所设计的Social Network。FriendShipGraph中的所有方法都需要用Graph来实现。

3.2.1 FriendshipGraph

(1)声明一个Graph类型的变量,将泛型替换为<Person>类。然后初始化,生成一个空图。

 

(2)addVertex

用迭代器遍历顶点集合vertices,若存在顶点与person名称重复,则返回false;若不重复,则将person加入图中,并返回true。

 

(3)addEdge

使用Graph中的set方法来加入图中的边即可。

 

(4)getDistance

用广度优先算法搜索最短路径,只是将实验一中的方法用Graph实现即可。

 3.2.2 Person

由于FriendshipGraph中的方法都可以利用P1中的Graph实现,所以Person中只需存放姓名以及相关方法,为了防止数据泄露,要设置为private final关键字。

 3.2.3 客户端main()

直接将Lab1中的main函数复制过来即可

 3.2.4 测试用例

使用实验一中的测试方法

 

 

 3.2.5 提交至Git仓库

使用git add添加文件

     git commit提交到本地

     git push推送到GitHub

 

在这里给出你的项目的目录结构树状示意图。

 4 实验进度记录

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

日期

时间段

计划任务

实际完成情况

2023.3.21

16:00-21:00

编写Poetic Walks的problem1、problem2

编写时遇到困难,未能按时完成

2023.3.22

10:00-12:00

编写Poetic Walks的problem1、problem2

按时完成

2023.3.25

13:00-14:00

编写Poetic Walks的problem3

按时完成

2023.3.25

25:00-18:00

编写Poetic Walks的problem4

在编写Graph potery slam问题时遇到困难,未能按时完成

2023.3.26

9:00-11:00

编写Poetic Walks的problem4中的Graph potery slam

按时完成

2023.3.28

15:30-18:30

编写Re-implement the Social Network in Lab1

按时完成

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

遇到的难点

解决途径

第一次自己编写ADT,对编写方法并不熟悉,遇到许多困难

通过查阅资料以及向身边的同学请教,最后基本掌握编写方法

在编写Poetic Walks中Graph potery slam问题时,对句子拓展问题理解有偏差,导致一直编写错误

向同学请教并且再次仔细分析该问题,最后顺利解决问题

编写测试用例时,代码的覆盖率总是不高,不能达到良好的对代码进行测试的结果

再次学习测试用例的编写方法,使用等价类划分,尽量考虑到边界值等容易忽略但又很容易发生错误的地方,提高测试用例的质量

6 实验过程中收获的经验教训、感想
6.1 实验过程中收获的经验教训(必答)

在本次实验中,我学会了基本的ADT编写方法以及泛型使用的优越性,并且了解了在完成代码编写时规约的重要性。同时我也感受到自己对于JAVA语言理解掌握的不足,在实验过程中遇到很多困难,以后还应该加强学习。

6.2 针对以下方面的感受(必答)

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

面向ADT编程,主要是通过各个模块之间互相调用来实现功能;

直接面向应用场景编程,是利用各个方法之间的相互调用,以整个过程为单位进行编程。

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

泛型可以使我们不必考虑变量的类型对他们进行相同的操作,会简化编程过程,更加便利、提高编程效率。

但是不使用泛型可以实现一些更加具体的方法。

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

可以比较客观的来对后续的程序进行测试,比后续再进行编写更加节省时间并且准确性也更高。

我比较能够适应这种测试方法。

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

避免了大量的重复代码,大大提高了程序编写的效率,节约了开发时间以及开发成本。

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

这些过程是对程序安全性、健壮性,设计框架的条理性与逻辑性的保障,它确保了程序可以对各种输入进行对应的处理,同时保证了非法数据不会破坏程序的进行。

在以后的编程过程中,我们应该保持这种良好的习惯。

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

因为是第一次接触ADT的编写,对其掌握还不够深刻,所以对我来说本实验的工作量和难度都偏大,但是实验时间较为充裕,所以可以完成该实验。

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

通过对《软件构造》的理论课学习以及在实验中的练习,我更好地掌握了面向对象的程序编写过程,并且有了一定的程序框架设计能力,也学习到了更多理论知识,自身能力有了很大的提升。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值