哈工大软件构造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菜单 →“帮助” → 安装新软件;
“安装”对话框中,在“ 工作日期”中输入http://update.eclemma.org/

根据指示正常安装即可
在这里给出你的GitHub Lab2仓库的URL地址(Lab2-学号)。
https://github.com/ComputerScienceHIT/HIT-Lab2-1181910201
3 实验过程
请仔细对照实验手册,针对三个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。
3.1 Poetic Walks
实现一个图graph的模块,基于此模块,根据语义库进行诗歌创作
1. 实现Graph的String类型接口类,之后将String拓展为泛型L类;
2. 创建Graph类的add、set、remove、vertices、sources、targets等方法;
3. 基于创建好的Graph类,实现GraphPoet类,将语义库存入graph图中,然后利用GraphPoet类,根据graph中语义库的信息,对输入文本进行处理,若输入文本的两个单词之间存在桥接词,则插入桥接词;若存在多个单一桥接词,则选取边权重较大者。最终得到由输入文本创作的诗歌,
3.1.1 Get the code and prepare Git repository
创建本地仓库
git init
下载实验代码
git clone
https://github.com/rainywang/Spring2020_HITCS_SC_Lab2/tree/master/P1
连接远程仓库
git remote 
https://github.com/ComputerScienceHIT/HIT-Lab2-1181910201
添加到本地仓库
git add .
提交到本地仓库
git commit -m
初次上传到远程仓库
git push -u origin master
之后
git push origin master
 
 
3.1.2 Problem 1: Test Graph <String>
针对每个方法进行等价类划分的测试






覆盖率:

3.1.3 Problem 2: Implement Graph <String>
以下各部分,请按照MIT页面上相应部分的要求,逐项列出你的设计和实现思路/过程/结果。
3.1.3.1 Implement ConcreteEdgesGraph
1. 实现Edge类
数据段-边的权值weight,边的起点source,终点target

Edge中的方法
| Edge | 构造方法,初始化边的权值weight,起点source,终点target | 
| checkRep | 检查不变性,边不为空且权值非负 | 
| getSource | get方法返回起点source | 
| getTarget | get方法返回终点targe | 
| getWeight | get方法返回权值weight | 
| toString | " Source:" + this.source + ",Target:" + this.target + ",Weight:" +this.weight | 
2. 实现ConcreteEdgesGraph类
数据段:顶点集vertices和动态链表edges

ConcreteEdgesGraph中的方法:
| ConcreteEdgesGraph | 构造方法 | 
| checkRep | 检查不变性,edges中边的source与target在vertices中,权值weight大于0 | 
| add | 参数为新顶点,点不在原图,添加成功-true 否则-false | 
| set | 参数为边的起点source边的终点target边的权重weight,列表edges中添加一条边,若起点终点相同或权值为负,添加失败返回;若是新边,权值为正,将两点添加至vertices,边添加到edges.若是已存在的边,权值为正,更新边的权值,返回上一条边的权值,权值为0,删除此边 | 
| remove | 参数为需移除的顶点,删除顶点,与此点相连的边也一并删除,原图有此顶点返回true,若无则返回false | 
| vertices | 返回得到图中所有顶点的HashSet集 | 
| sources | 参数为目标顶点,返回得到所有以该点为终点的边的起点及权值,储存到Map | 
| targets | 参数为目标顶点,返回得到所有以该点为起点的边的终点及权值,储存到Map | 
| toString | 返回字符串,包含顶点数,边数,各边及其权重 | 
3.测试,增加testToString部分即可


覆盖率

3.1.3.2 Implement ConcreteVerticesGraph
1. 实现Vertex类:
数据段 -V表示顶点,Sources表示以该顶点为终点的边的起点表,Targets表示以该顶点为起点的边的终点表,Map中String为顶点的对点,Integer为边的权值

Vertex中的方法
| Vertex | 初始化构造方法,参数为顶点 | 
| checkRep | 检查不变性,顶点不空,权值为正 | 
| getV | 返回顶点V | 
| sources | 返回所有以该点为终点的边,Map中为边的起点及权值 | 
| targets | 返回所有以该点为终点的边,Map中为边的起点及权值 | 
| setSource | 参数为待加入的起点与权值,该点为终点时,将边的起点和权值加入到 Map Sources中,若权值小于等于0,返回0,若权值为正,当起点已存在时,更新权值,返回原来的权值,起点不存在则添加新点 | 
| setTarget | 参数为待加入的终点与权值,该点为起点时,将边的终点和权值加入到 Map Target中,若权值小于等于0,返回0,若权值为正,当终点已存在时,更新权值,返回原来的权值,终点不存在则添加新点 | 
| removeEdge | 参数为对点,在Sources或Targets表中,删除与顶点相连某条边的对点,返回原来的边长 | 
| toString | this.V.toString()+"-Sources:"+this.Sources.toString()+" Targets:"+this.Targets.toString()+"\n" | 
2. 实现ConcreteVerticesGraph类
数据段-Vertex构成的列表vertices

ConcreteVerticesGraph中的方法:
| ConcreteVerticesGraph | 构造方法 | 
| checkRep | 检查不变性,权值为正,顶点非空,起点终点数相同 | 
| add | 参数为顶点,在图中添加一个顶点,若图中存在该点,添加失败return false;若添加成功,return true | 
| set | 参数为边的起点,边的终点,边的权值,添加一条边(在起点终点各自的vertex类里添加各自的对点)若起点终点相同或权值为负,添加失败返回,若是新边,权值为正,将两点添加至vertices,各自类中添加边,权值为0,只将两点添加至vertices,若是已存在的边,权值为正,更新边的权值,返回上一条边的权值,权值为0,删除此边 | 
| remove | 参数为需移除的顶点,删除顶点,与此点相连的边也一并删除,原图有此顶点返回true,若无则返回false | 
| vertices | 返回得到图中所有顶点的点集 | 
| sources | 参数为目标顶点,返回得到所有以该点为终点的边的起点及权值,储存到Map | 
| targets | 参数为目标顶点,返回得到所有以该点为起点的边的终点及权值,储存到Map | 
| toString | 各顶点的边对点及其权重 | 
3. 测试,增加testToString部分即可


覆盖率

3.1.4 Problem 3: Implement generic Graph<L>
3.1.4.1 Make the implementations generic
将类型更改为
publicclass ConcreteEdgesGraph<L> implements Graph<L>{ ... }class Edge<L>{ ... }
和:
publicclass ConcreteVerticesGraph<L> implements Graph<L>{ ... }class Vertex<L>{ ... }
已经声明了类型为Edge或 的变量List<Edge>,成为Edge<L>和List<Edge<L>>
只需按以上规则对Graph<String>进行重构即可,代码整体逻辑框架不变。
重构后测试结果




3.1.4.2 Implement Graph.empty()
public static Graph<String> empty() {
    return new ConcreteEdgesGraph();
}
返回空的实例
3.1.5 Problem 4: Poetic walks
基于创建好的Graph类,实现GraphPoet类,将语义库存入graph图中,然后利用GraphPoet类,根据graph中语义库的信息,对输入文本进行处理,若输入文本的两个单词之间存在桥接词,则插入桥接词;若存在多个单一桥接词,则选取边权重较大者。最终得到由输入文本创作的诗歌
3.1.5.1 Test GraphPoet
添加一段测试,生成诗歌是否与预期相同即可


覆盖率

3.1.5.2 Implement GraphPoet
数据段-新的空表

GraphPoet,按行读入文本文件,String.split()分割为数组String.toLowerCase()小写。构建图,相邻的单词加边。首先要在加边前通过Graph.add()加点,加边时要判断是否存在:由于Graph.set()能返回之前加的边的值,以此来判断是否存在,存在则在之前的值加一(之前的边的值保存为temp_weight)。

poem当相邻两个单词任意一个不在之前创建的图里,则将后者单词加入,当存在时,Bridge长度只能为2,分别求两个单词的sources和targets,将该Map转换为Set求交集;若交集为空,则无桥,若交集不空,则在交集中找最短的桥(可以在Map的value中查询weight)。

3.1.5.3 Graph poetry slam
测试



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

3.1.7 Before you’re done
请按照http://web.mit.edu/6.031/www/sp17/psets/ps2/#before_youre_done的说明,检查你的程序。
如何通过Git提交当前版本到GitHub上你的Lab2仓库。

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

3.2 Re-implement the Social Network in Lab1
同Lab1类似,用Person和FriendshipGraph两个类模拟社交网络图,Person模拟图的顶点,FriendshipGraph模拟关系,getDistance能够计算出每两个Person之间的最短路径,但要用3.1中的Graph ADT中的方法来实现
3.2.1 FriendshipGraph类
数据段:

一个由Person类组成的Graph类型图,初始为空
方法:
addVertex():调用graph.add()添加点。
addEdge():调用graph.set()两次,添加双向边,权值为1,返回旧边的权值。
int getDistance():判断起止点是否相等。再新建Map<Person, Integer> disance存储从起始点开始到该Person的距离,Map<Person, Boolean> visited表示该Person是否访问过。将两个Map初始化后,把起点标记为已经访问。然后开始BFS搜索,找到终点为止,返回最短距离。

3.2.2 Person类
数据段name,构造方法Person赋值,get方法getName返回数据段name

3.2.3 客户端main()
Lab1中的main复制过来即可


3.2.4 测试用例


覆盖率

3.2.5 提交至Git仓库
在这里给出你的项目的目录结构树状示意图。

4 实验进度记录
请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。
每次结束编程时,请向该表格中增加一行。不要事后胡乱填写。
不要嫌烦,该表格可帮助你汇总你在每个任务上付出的时间和精力,发现自己不擅长的任务,后续有意识的弥补。
| 日期 | 时间段 | 计划任务 | 实际完成情况 | 
| 2021.6.10 | 18.00-22.00 | 完成Graph<String>部分 | 对实验要求有了初步认识,细节未完成 | 
| 2021.6.11 | 18.00-23.00 | 完成poet之前的部分 | 完成 | 
| 2021.6.12 | 12.00-15.00 | 完成poet部分 | 完成 | 
| 2021.6.13 | 12.00-15.00 | 完成Person部分 | 完成 | 
5 实验过程中遇到的困难与解决途径
| 遇到的难点 | 解决途径 | 
| 
 MIT的实验要求不明确,英文难懂 
 | 翻译软件初步翻译后,仍有许多细节模糊,每一句再具体翻译 | 
| 
 对javadoc要求的完善方法具体实现需要的数据结构不清楚 
 | 上网,翻阅教材查阅相关数据结构 | 
| 
 
 
 | 
 | 
6 实验过程中收获的经验、教训、感想
6.1 实验过程中收获的经验和教训
1.java编程经验少,对相关数据结构不熟悉,javadoc格式的注释不规范
2.对ADT与OOP有了更深刻的理解
3.对相关数据结构,有了更深的理解。
6.2 针对以下方面的感受
(1) 面向ADT的编程和直接面向应用场景编程,你体会到二者有何差异?
面向对象以抽象,类,继承,对象等方法为基础,就像制造汽车时,先将汽车分成多个部分,然后具体生产每一部分的零件再组装,而面向过程像是从零件直接组装。
(2) 使用泛型和不使用泛型的编程,对你来说有何差异?
泛型能适应更多的情况,更加灵活多变。
(3) 在给出ADT的规约后就开始编写测试用例,优势是什么?你是否能够适应这种测试方式?
可以及时修改,保证代码正确性与规范性,能
(4) P1设计的ADT在多个应用场景下使用,这种复用带来什么好处?
增加代码利用率,避免重复造轮子
(5) P3要求你从0开始设计ADT并使用它们完成一个具体应用,你是否已适应从具体应用场景到ADT的“抽象映射”?相比起P1给出了ADT非常明确的rep和方法、ADT之间的逻辑关系,P3要求你自主设计这些内容,你的感受如何?
体会到了面向对象编程的优点,有轮子时很容易实现,造轮子很困难。
(6) 为ADT撰写specification, invariants, RI, AF,时刻注意ADT是否有rep exposure,这些工作的意义是什么?你是否愿意在以后编程中坚持这么做?
防止内部数据被外部修改,愿意
(7) 关于本实验的工作量、难度、deadline。
大,难,紧
(8) 《软件构造》课程进展到目前,你对该课程有何体会和建议?
上课内容太过宽泛,课后辅导较少,难度较大,实验和课堂结合不好。
2021年春季学期
计算学部《软件构造》课程
Lab
1实验报告
| 姓名 | 李金宣 | 
| 学号 | 1181910201 | 
| 班号 | 1903002 | 
| 电子邮件 | 
 | 
| 手机号码 | 
 | 
1 实验目标概述
本次实验通过求解三个问题,训练基本Java编程技能,能够利用Java OO开发基本的功能模块,能够阅读理解已有代码框架并根据功能需求补全代码,能够为所开发的代码编写基本的测试程序并完成测试,初步保证所开发代码的正确性。另一方面,利用Git作为代码配置管理的工具,学会Git的基本使用方法。
l 基本的Java OO编程
l 基于Eclipse IDE进行Java编程
l 基于JUnit的测试
l 基于Git的代码配置管理
2 实验环境配置
JDK环境,大一学习Javaee课程时配置的jdk8环境,环境变量等配置时遇到一些问题,通过网络搜索自学解决。
配置Eclipse环境时,一开始按照指导手册的教程一步步安装,中间导入URL等环节出现许多问题,于是直接放弃指导手册,自己一路点击next与finish进行安装,所幸成功安装eclipse。由于对全英文开发环境不太熟悉,网上搜索了eclipse简体中文环境的配置方法,具体参考
https://blog.csdn.net/qq_43015730/article/details/89225747
下载的eclipse自带Junit环境,但需要在eclipse设置中自行调用,一开始并不太懂应该怎么调用Junit,在运行P2的turtle的test文件时,因未配置Junit环境导致出错,在报错的行ctrl+1进行修改,成功配置Junit4环境。
在使用git的过程中遇到了非常多的问题,前后花了很长时间才将git环境配置好,一开始按照实验指导手册的Git指导书学习,但指导书内容过于繁杂,重点不突出,很多细节问题都没有解答,于是直接放弃指导书,同学间交流和网络上自行搜索成功配置好Git环境。
参考过非常多网站,如
https://www.cnblogs.com/dfsxh/articles/10959383.html
在这里给出你的GitHub Lab1仓库的URL地址。
https://github.com/ComputerScienceHIT/HIT-Lab1-1181910201
3 实验过程
请仔细对照实验手册,针对四个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但无需把你的源代码全部粘贴过来!)。
为了条理清晰,可根据需要在各节增加三级标题。
3.1 Magic Squares
要求1:在 main()函数中调用五次 isLegalMagicSquare()函数,将 5 个文本文件名作为参数输入,读入文本数据,判断输入的数据能否构成一个MagicSquare,若是则返回true,若不是或格式错误,则返回false且说明原因。
要求2:对给出的generateMagicSquare函数扩展,根据参数n生成一个MagicSquare并写入文本6.txt中,然后判断其是否为MagicSquare。输入为奇数能生成MagicSquare返回true,输入偶数或者负数会返回false。
3.1.1 isLegalMagicSquare()
设计思路:首先读入txt文本文件,然后进行判断题目要求的三个条件:
1. 行列数不相等,并非矩阵:每读入一行row++,计算总行数,将每一行按照\t分隔存入数组,判断每一行的列数是否与行数相等,若存在不相等,返回false。
2. 矩阵中的某些数字并非正整数:每一行按照\t分隔存入数组后,判断数组元素有无”-”或”.”,有则说明有负数或小数,返回false
3. 数字之间并非使用\t分割:对Integer.valueOf使用try catch方法,若不是以 \t作为分隔符则抛出异常信息,返回false。
对错误类型进行判断输出错误类型并返回false,当判断完毕没 格式错误时,将读入的数据存入到矩阵中,判断每一行,每一列,对角线的和是否相等,满足MagicSquare 则返回true,若有不相等则返回false
测试结果:
3.1.2 generatelMagicSquare()
流程图
合法输入判断
测试样例
3.2 Turtle Graphics
要求:1.完善drawSquare函数,画出一个正方形
2.完善calculateRegularPolygonAngle函数计算正多边形内角
3.完善calculatePolygonSidesFromAngle函数,由正多边形内角 得到边数
4.完善drawRegularPolygon函数,画正多边形
5.完善calculateBearingToPoint计算从一个点到另一个点所转过的角度,
6.完善calculateBearings函数,给定一组点,计算每次转过的角度并返回集合,
7.完善convexHull函数计算一系列点中的凸包,使用junit进行单元测试。
8.调用函数绘制自己的图形
3.2.1 Problem 1: Clone and import
从实验手册的网站git clone下载P2的包,解压导入eclipse项目中。
1.获取秘钥:
2.找到秘钥并复制添加到github上;
本地Git提交,push到GitHub:
1. git add ;
2. git commit -m " " ;
3. git push
参考https://www.cnblogs.com/dfsxh/articles/10959383.html
3.2.2 Problem 3: Turtle graphics and drawSquare
行进四次,每次转90度
测试结果
3.2.3 Problem 5: Drawing polygons
正多边形内角=(边数-2)*180/边数
画多边形时每次前进偏转外角度数即可
3.2.4 Problem 6: Calculating Bearings
调用atan2函数得到两点间偏转弧度,toDegree转换成角度,减去当前偏角即为偏转角度,计算一组点,反复调用两点的函数即可
3.2.5 Problem 7: Convex Hulls
利用Gift wrapping算法计算凸包,先找到最左下角的点作为初始点加入集合,然后比较剩余点到此点的偏转角,找到偏转角最小的加入集合,当偏转角相同时,找到最长的一条边的点加入集合,直到返回初始点最后得到凸包的点集。
//这部分源代码过长贴不下,请看源文件
3.2.6 Problem 8: Personal art
3.2.7 Submitting
Junit测试
3.3Social Network
用Person和FriendshipGraph两个类模拟社交网络图,Person模拟图的顶点,FriendshipGraph模拟关系,getDistance能够计算出每两个Person之间的最短路径。
3.3.1设计/实现FriendshipGraph类
定义Person数组来储存所有的顶点,构造方法
addVertex添加对象,若新对象名字与已有名字重复,打印错误,退出
addEdge添加边(顶点间的关系),在Person a对象数组friend的里添加b,单向
因为边权重为1,可以使用广度优先搜索求两点间最短路径,调用类HashMap,用temp临时存储a1到各个点的最短距离,调用队列,将a1入队后按广度优先搜索的方法不断入队出队,更新temp中各顶点当前最短路径,直到有到a2的路径为止,返回最短距离
3.3.2设计/实现Person类
3.3.3设计/实现客户端代码main()
3.3.4设计/实现测试用例
给出你的设计和实现思路/过程/结果。
对于addVertex,设计用例,建立四个Person对象,执行addVertex,判断vertex里面这些对象。
对于addEdge,设计test用例,建立四个Person对象,执行addVertex后,执行addEdge然后判断每个对象的friend中是否包含即可。
对于getDistance,设计test用例t,建立四个Person对象,执行addVertex后,执行addEdge后,最短距离正确即可。
4 实验进度记录
请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。
每次结束编程时,请向该表格中增加一行。不要事后胡乱填写。
不要嫌烦,该表格可帮助你汇总你在每个任务上付出的时间和精力,发现自己不擅长的任务,后续有意识的弥补。
| 日期 | 时间段 | 任务 | 实际完成情况 | 
| 2021-05-19 | 晚 | 配置环境 | Git配置未完成 | 
| 2021-05-20 | 18.:00- | 配置环境 | 完成 | 
| 2021-05-21 | 10:00-13:00 | 编写P1的isLegalMagicSquare函数 | 完成 | 
| 2021-05-21 | 15:00-16:00 | 编写P1的generateMagicSquare函数 | 完成 | 
| 2021-05-22 | 10:00-14:00 | 完成P2 | 完成 | 
| 2021-05-22 | 17:00-21:00 | 完成P3 | 完成 | 
| 
 | 
 | 
 | 
 | 
5 实验过程中遇到的困难与解决途径
| 遇到的困难 | 解决途径 | 
| Git配置出现问题 
 
 | 网上自己搜,与同学交流学习 | 
| P2测试类时出现问题 
 
 | Eclipse的junit环境未设置,在报错的行ctrl+1进行修改,成功配置Junit4环境。 | 
| 
 P2对礼物包装算法不熟悉 
 | 网络上搜索算法详细介绍,参考算法的相关代码编写 | 
| P3对Java的广度优先算法编写不太熟悉 | 查阅Java中队列,哈希表等相关类的介绍和用法,成功使用并优化了代码 | 
6 实验过程中收获的经验、教训、感想
6.1 实验过程中收获的经验和教训
1.使用java次数少,对java语法不熟悉,许多地方代码优化不好
2.对Git配置不熟悉,出现许多问题
3.对java语言有了更深的理解。
6.2 针对以下方面的感受
(1) Java编程语言是否对你的口味?还好,有一定java基础但不熟练,Java可使用的类与库非常多,相比c语言可以使代码的编写更加容易,代码更加简洁。
(2) 关于Eclipse IDE;以前用过,用户界面也比较良好,上手也容易,暂时未遇到太多问题
(3) 关于Git和GitHub;环境配置非常麻烦,实验手册的指导完全没有重点,不知道从哪学起,全依靠自己上网搜索和同学交流,希望这门课以后能把Git环境的配置详细地指导给大家,而不是直接照搬MIT的指导手册。
(4) 关于CMU和MIT的作业;虽然有一定难度,但层层递进,锻炼编程能力,Java编程的收获很大。
(5) 关于本实验的工作量、难度、deadline;有一定难度,工作量大,虽然两周时间实验其实还算充裕,但课程时间与其他课程ddl冲突,开课第一周恰逢自动机期末考试和csapp实验ddl,导致实际上的实验时间被大大缩短,希望教务处能平衡好这几门课ddl的冲突.
(6) 关于初接触“软件构造”课程;
实验收获还是很大的,但个人觉得平时上课讲的东西太抽象宽泛,缺乏实际联系,很难理解什么意思,很多同学也听得不知所云,应对考试也就是背知识点做题,很难有实际收获,然而这些部分却占了成绩的大头,希望课程考核和教学方式能有所改革,能更多侧重于实验部分或者提升平日课程内容的质量。
 
                    
                     
                    
                 
                    
                

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号