哈工大软件构造lab2---实验心得
- 实验目标概述
本次实验训练抽象数据类型(ADT)的设计、规约、测试,并使用面向对象编程(OOP)技术实现ADT。具体来说:
l针对给定的应用问题,从问题描述中识别所需的ADT;
l设计ADT规约(pre-condition、post-condition)并评估规约的质量;
l根据ADT的规约设计测试用例;
lADT的泛型化;
l根据规约设计ADT的多种不同的实现;针对每种实现,设计其表示(representation)、表示不变性(rep invariant)、抽象过程(abstraction function)
l使用OOP实现ADT,并判定表示不变性是否违反、各实现是否存在表示泄露(rep exposure);
l测试ADT的实现并评估测试的覆盖度;
l使用ADT及其实现,为应用问题开发程序;
在测试代码中,能够写出testing strategy并据此设计测试用例。
- 实验环境配置
进入eclemma官网下载文件安装并使用eclemma
- 实验过程
请仔细对照实验手册,针对两个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。
- Poetic Walks
这个实验的主要目的是测试 ADT 的规约设计和 ADT 的多种不同的实现,并练习 TDD 测试优先编程的编程习,在后面练习 ADT 的泛型化。
- Get the code and prepare Git repository
从下图处获取所需代码,创建新的项目后按照要求建立目录。
如何从GitHub获取该任务的代码、在本地创建git仓库、使用git管理本地开发。
- Problem 1: Test Graph <String>
这里要完成提供的单元测试中的Junit测试类GraphInstanceTest.java。首先根据实验要求可知,GraphInstanceTest.java是对Graph类的单元测试,所以我们需要知道Graph类包含的方法,并根据给定的函数规约了解方法对应的设计要求:
testAdd():测试是否能加入一个新的顶点,如果返回true则成功,如果返回false则没能加入。
testSet():加入一条新的边,测试返回值是否是0,如果是0则成功,反之失败。再继续向图中以一定权重加刚才加入的边,测试返回值是否是刚才的权重。最后以0权重加入这条边,判断是否存在边
testRemove():向图中加入一定的边,删除某顶点,测试被删除顶点的边是否依然存在
testVertices():向图中加入顶点测试集合是否正确
testSources():向图中加入顶点和边测试是否返回源头点和权重
testTargets():向图中加入顶点和边测试某个顶点相连是否正确
覆盖率为:
Problem 2: Implement Graph <String>
以下各部分,请按照MIT页面上相应部分的要求,逐项列出你的设计和实现思路/过程/结果。
- Implement ConcreteEdgesGraph
实现ConcreteEdgesGraph类,即通过将边当作基本单位来表示图。这里给出了ConcreteEdgesGraph类的框架同时要求使用辅助类Edge实现ConcreteEdgesGraph类,并编写相关的单元测试。
(一)实现Egde类:
1)根据定义,Edge中应包含源点、终点、权值三个成员,依次给出其定义:
private final L source;
private final L target;
private final int weight;
2)在Edge中需要实现的方法如下:
Edge:初始化构造方法,初始化新边的两个点和边的权值
checkRep:检查表示不变性,边不为空且权值大于等于0
getsource:返回边的一个点source
gettarget :返回边的另外点target
getweight:返回边的weight
toString:返回一条边的字符串,形式为“起点->终点权重为xx”
3)随后给出其AF、RI等信息:
Abstraction function:
AF(source) =边的起点
AF(target) =边的终点
AF(weight) =边的权值
Representation invariant:
lweight >=0 source和target不为空
Safety from rep.exposure:
将source,target,weight设置为private
4)Test策略:
(二)实现ConcreteEdgesGraph类
1)ConcreteEdgesGraph的字段中应该包括顶点set表和边list表,定义私有类型为:
2)在ConcreteEdgesGraph中需要实现的方法为:
ConcreteEdgesGraph |
构造方法 |
checkRep |
检查表示不变性,edges长度是大于0的实数,有起始的节点 |
add |
顶点不为空时,添加一个顶点进入点表中 |
set |
输入source,target,weight,分别为边的起点、终点和权值。若权值为负,返回-1。若权值为正且新边已经存在,则除去原边并添加新边。若权值为正且新边不存在,则直接添加新边。若权值为0且新边已经存在,则出去原边。只要改变了原边权值,都返回原边权值,没有权值则返回0 |
remove |
除去某个点及与它相邻的所有边。只需要遍历edges,寻找是否有边的起点或者终点为该点,直接删去即可,使用迭代器实现。 |
vertices |
返回所有的点集 |
sources |
输入一个终点,返回与它相连的所有边和起点构成的Map |
targets |
输入一个起点,返回与它相连的所有边和终点构成为的Map |
toString |
将整个图中所有点的指向转化为一条字符串输出 |
3)AF,RI和Safety from rep exposure为:
Abstraction function :
AF(vertices)=图中的点
AF(edges)=图中的边
Representation invariant:
edges长度是大于o的实数,有起始的节点
vertex点必须包含在vertices中
两个点之间最多只有一条边
Safety from repexposure:
将vertices和edges设置为private
由于vertices和edges是mutable,所以在返回他们时进行了defensive copies
4)Test策略:
正在上传…重新上传取消
Test结果:
正在上传…重新上传取消
覆盖率为:
正在上传…重新上传取消
- Implement ConcreteVerticesGraph
(一)实现Vertices类:
(1).Vertices的字段中应当包括点的名字,点的源点表Map,点的终点表Map,定义私有类型的表如下图所示:
正在上传…重新上传取消
(2).在Vertices需要实现的方法:
Vertex |
初始化构造方法,用点的名字创建 |
checkRep |
检查表示不变性,每个边的权值应该大于0 |
getmark |
返回点的名字mark |
getsource |
返回能到达该点的所有点和边构成的Map |
gettarget |
返回某个点能到达的所有点和边构成的Map |
addsource |
在源点Map中加入某源点,若weight不为0,则将其加入source中(若源点已存在,则更新其weight并返回原weight,不存在则直接构建新点并返回0)。若weight为0,则移除源点(不存在返回0,存在返回原weight) |
addtarget |
在终点Map中加入某终点,若weight不为0,则将其加入target中(若终点已存在,则更新其weight并返回原weight,不存在则直接构建新点并返回0)。若weight为0,则移除终点(不存在返回0,存在返回原weight) |
removesource |
在源点表中删除某起始点,并返回旧的边长 |
removetarget |
在终点表中删除某终点,并返回旧的边长 |
toString |
得到一个点的字符串表示 |
(3).AF,RI和Safety from rep exposure:
正在上传…重新上传取消
4)Test策略:
(二)实现ConcreteVerticesGraph类
(1).ConcreteVerticesGraph的字段为Vertex构成的List,定义私有类型的表如下图所示:
(2).在ConcreteVerticesGraph需要实现的方法:
ConcreteVerticesGraph |
构造方法 |
checkRep |
检查表示不变性,vertices中不能有重复点 |
add |
顶点不为空时,添加一个顶点进入点表中 |
set |
输入source,target,weight,分别为边的起点、终点和权值。若权值为负,返回-1。若权值为正且新边已经存在,则除去原边并添加新边。若权值为正且新边不存在,则直接添加新边。若权值为0且新边已经存在,则出去原边。只要改变了原边权值,都返回原边权值,没有权值则返回0 |
remove |
除去某个点及与它相邻的所有边。只需要遍历vertices,寻找是否有与待删除点相同的名字的点直接删去即可,如果名字不相同,则在该点的源点表和终点表中寻找删去即可,使用迭代器实现。 |
vertices |
返回所有的点集 |
sources |
输入一个终点,返回与它相连的所有边和起点构成的Map |
targets |
输入一个起点,返回与它相连的所有边和终点构成为的Map |
toString |
将整个图中所有点的指向转化为一条字符串输出 |
(3).AF,RI和Safety from rep exposure:
(4).Test策略:
继承Graph的测试策略,只需要增加toString的测试即可
测试结果:
覆盖率:
- Problem 3: Implement generic Graph<L>
- Make the implementations generic
使用泛型实现即可:
在修改过程中通过eclipse提示的错误修改即可完成:
- Problem 4: Poetic walks
任务要求我们实现一个类,利用之前实现的图结构,能够将语料库转化为该种图结构,并且在图中搜索,完成对输入的诗句的句子进行扩充。
- Test GraphPoet
Test策略:
实现读入一系列满足要求的文件:
测试结果为:
覆盖率为:
- Implement GraphPoet
(1). GraphPoet的字段为String构成的Graph,定义私有类型的表:
(2). AF,RI和Safety from rep exposure:
(3).在GraphPoet中需要实现的方法:
GraphPoet |
输入文件的路径,一行一行读入,储存在List中,然后每次取相邻的元素,在图中添加新的边 |
checkRep |
检查不变性,必须保存从语料库文件生成的图 |
poem |
输入需要进行扩充的字符串,声明声明一个StringBuilder保存,每次读取一个词,当前词作为source,下一个词作为target,然后在garph中寻找source的终点表中是否有与target的源点表中相同的元素,并且找到权值最大的和的点加入source和target之间,具体实现为:正在上传…重新上传取消 返回扩充后的字符串 |
toString |
调用ConcreteEdgesGraph中的toString方法,将整个图中所有点的指向转化为一条字符串输出 |
- Graph poetry slam
在提供代码的基础上增加一个toString的输出:
运行main函数输出为:
- Before you’re done
请按照http://web.mit.edu/6.031/www/sp17/psets/ps2/#before_youre_done的说明,检查你的程序。
如何通过Git提交当前版本到GitHub上你的Lab2仓库。
在这里给出你的项目的目录结构树状示意图。
- Re-implement the Social Network in Lab1
这次实验要求我们基于Poetic Walks中定义的Graph<L>及其两种实现(本人使用的是ConcreteVerticesGraph<L>),实现Lab1中Social NetWorek中的各种功能,并且尽可能复用ConcreteVerticesGraph<L>中已经实现的方法,然后运行提供的main()和执行Lab1中的Junit测试用例,使之正常运行。
- FriendshipGraph类
(1).FriendshipGraph的字段为Person构成的ConcreteEdgesGraph,定义私有类型的表:
正在上传…重新上传取消
(2).在FriendshipGraph需要实现的方法:
FriendshipGraph |
构造方法 |
addVertex |
在图中增加新Person,只需要调用ConcreteEdgesGraph中的add即可: 正在上传…重新上传取消 |
addEdge |
为某个人增加朋友,a为这个人,b为增加的朋友,直接调用ConcreteEdgesGraph中的set即可: 正在上传…重新上传取消 |
getallprople |
直接返回即可: 正在上传…重新上传取消 |
getDistance |
得到两个人之间的最短距离。与Lab1类似,稍加修改即可: 实现此功能我们需要了解先广方式求最短路径的方法。首先我们需要知道若两个Person对象为同一个,则返回0。然后定义一个Map集合theway和一个Person队列myqueue,队列myqueue用来储存广搜的遍历结果,theway的Map集合用来储存广搜的所有元素及他们与第一个元素的距离。具体实现方法为首先将第一个元素c1入队,并且把第一个元素c1和下标0入集合,当队列非空时,弹出队首元素top,并且得到top在集合theway中的下标distance,然后定义一个Map为friend,执行personGraph.targets(top)得到队首元素的所有朋友的Map,然后定义Set为allfriend,对刚才的friend执行keySet()得到allfriend,只要allfriend中的元素与c2不同,就把这些元素全部入队,并且把这些元素及下标distance+1放入集合。只要队列非空,继续执行以上步骤,直到找到某个元素与c2相同并且返回这个元素在集合theway中的下标。如果直到队列为空还没找到c2,则返回-1: 正在上传…重新上传取消 |
main |
复制Lab1的即可 |
(3).AF,RI和Safety from rep exposure:
正在上传…重新上传取消
- Person类
(1).FriendshipGraph的字段为Person构成的ConcreteEdgesGraph,定义私有类型的表:
正在上传…重新上传取消
(2).在FriendshipGraph需要实现的方法:
Person |
没有重复名字则加入,构造方法 |
getmyname |
返回本人名字,直接返回即可 |
(3).AF,RI和Safety from rep exposure:
正在上传…重新上传取消
- 客户端main()
正在上传…重新上传取消
原实验报告所对应图输出运行结果:
正在上传…重新上传取消
- 测试用例
Test策略:
正在上传…重新上传取消
正在上传…重新上传取消
正在上传…重新上传取消
正在上传…重新上传取消
Test结果:
正在上传…重新上传取消
覆盖率:
正在上传…重新上传取消
- 提交至Git仓库
如何通过Git提交当前版本到GitHub上你的Lab2仓库。
https://github.com/ComputerScienceHIT/HIT-Lab2-120L021402.git
在这里给出你的项目的目录结构树状示意图。
正在上传…重新上传取消
- 实验进度记录
请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。
每次结束编程时,请向该表格中增加一行。不要事后胡乱填写。
不要嫌烦,该表格可帮助你汇总你在每个任务上付出的时间和精力,发现自己不擅长的任务,后续有 意识的弥补。
日期 |
时间段 |
计划任务 |
实际完成情况 |
5.21 |
18:00-22:00 |
P1中边图类 |
延时完成 |
5.22 |
16:00-22:30 |
完成P1边图类 |
完成 |
5.23 |
19:00-23:00 |
P1点图类 |
完成 |
5.24 |
18:00-22:30 |
完成P1点图类 |
完成 |
5.25 |
18:00-22:00 |
完成P1中的诗集类 |
延时完成 |
5.26 |
17:50-22:20 |
P1诗集类 |
完成 |
5.27 |
19:00-22:30 |
P1中点图和边图的test |
完成 |
5.28 |
20:00-22:40 |
完成P1除了测试外的报告 |
完成 |
5.29 |
14:00-20:30 |
P1的所有测试 |
完成 |
5.29 |
13:00-21:00 |
完成P2及测试 |
延时完成 |
- 实验过程中遇到的困难与解决途径
遇到的难点 |
解决途径 |
刚开始写P1时不太明白要求,不太理解 |
多次揣摩出题人意图 |
不太理解泛型 |
在CSDN上学习使用 |
- 实验过程中收获的经验、教训、感想
java的使用还是不够熟练,需要多加练习。在自行设计多种类来实现功能的情况下,自己设计的很多类之间有很多重复和矛盾的部分,很多关系弄不清楚,代码很冗杂,测试起来也较麻烦。
- 面向ADT的编程和直接面向应用场景编程,你体会到二者有何差异?
面向对象能够每次完成对某个对象的编程,与面向过程的编程的思路完全不一样。
- 使用泛型和不使用泛型的编程,对你来说有何差异?
泛型能够适应更多的变化,更加灵活。
- 在给出ADT的规约后就开始编写测试用例,优势是什么?你是否能够适应这种测试方式?
能够保证代码的正确性,及时修改。不适应。
- P1设计的ADT在多个应用场景下使用,这种复用带来什么好处?
可以提高代码的利用率,减少重复。
- 为ADT撰写specification, invariants, RI, AF,时刻注意ADT是否有rep exposure,这些工作的意义是什么?你是否愿意在以后编程中坚持这么做?
最开始一头雾水,后来通过慢慢分析对每个类进行了实现,但是还是很多方法用的很繁琐,并且很多类很重复,一些功能没有用到。
- 关于本实验的工作量、难度、deadline。
防止内部变量被外部修改。很繁琐,写但了更好。
- 《软件构造》课程进展到目前,你对该课程有何体会和建议?
工作量很大。
哈工大软件构造lab2---实验心得相关推荐
- 哈工大软件构造lab2实验报告
1 实验目标概述 2 实验环境配置 3 实验过程 3.1 Poetic Walks 3.1.1 Get the code and prepare Git repository 3.1.2 Proble ...
- 哈工大软件构造Lab2实验
- 软件构造lab2 - 实验报告
软件构造lab2 - 实验报告 1.实验目标概述 2.环境配置 3.实验过程 3.1Poetic Walks 3.1.1Get the code and prepare Git repository ...
- 哈工大2020软件构造Lab2实验报告
本项目于3.17日实验课验收,请放心参考 参考时文中有给出一些建议,请查看 基本更新完成 2020春计算机学院<软件构造>课程Lab2实验报告 Software Construction ...
- (软件构造)2022哈工大软件构造 lab2内容以及心得
2022年春季学期 计算学部<软件构造>课程 Lab 2实验报告 姓名 艾浩林 学号 120L021917 班号 2003006 电子邮件 2017869860@qq.com 手机号码 1 ...
- HIT 软件构造 lab2实验报告
2020年春季学期 计算机学院<软件构造>课程 Lab 2实验报告 学号 1180300223 班号 1803002 目录 1 实验目标概述 1 2 实验环境配置 1 3 实验过程 1 3 ...
- 哈工大软件构造lab2总结
目录 1 实验目标概述··· 1 2 实验环境配置··· 1 3 实验过程··· 1 3.1 Poetic Walks· 1 3.1.1 Get the code and prepare Git re ...
- 软件构造 Lab2 实验报告
2021年春季学期 计算学部<软件构造>课程 Lab 2实验报告 姓名 王雨宁 学号 1190201118 班号 1903006 电子邮件 1756840811@qq.com 手机号码 1 ...
- 哈工大软件构造Lab1实验报告
2020年春季学期 计算机学院<软件构造>课程 Lab 1实验报告 目录 1 实验目标概述... 1 2 实验环境配置... 1 3 实验过程... 1 3.1 Magic Squares ...
最新文章
- 刚刚,2021中国最好学科排名发布:北大、清华、人大中国顶尖学科居前三
- Ubuntu 16.04下截图工具Shutter
- Eclipse配置Tomcat和JDK方法
- java基础之访问控制符
- php正则表达式程序,php正则表达式 Web程序 - 贪吃蛇学院-专业IT技术平台
- 中信证券:维持贝壳“买入”的投资评级
- mysql update 批量更新_mysql 批量更新的两种方法
- centos7当中的systemd及systemctl(节选)
- UltraISO制作linux启动盘(包含写入不完整解决方法)
- 树莓派安装TeamViewer
- K3 官改新手小白配置阿里DDNS 超级详细
- centos 文件搜索命令
- L1-061 新胖子公式 (10 分)C语言
- itest考试切屏能检测出来吗_itest测试
- 网站云服务器资料本地备份,云服务器数据备份到本地
- 半加器设计(结构描述法)
- Java正则匹配淘口令
- 《张萌:高效能人士的自我管理》学习笔记
- 新颖的自我介绍_简单新颖的自我介绍范文
- 产品经理的分类和职责