2021年春季学期计算学部《软件构造》课程Lab 2实验报告

2024-01-02 07:50

本文主要是介绍2021年春季学期计算学部《软件构造》课程Lab 2实验报告,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1实验目标概述

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

2实验环境配置

在之前的基础上安装配置 EclEmma,https://www.eclemma.org/有教程,主要过程如下:

  1. From your Eclipse menu select Help → Eclipse Marketplace.
  2. Search for “EclEmma”.
  3. Hit Install for the entry “EclEmma Java Code Coverage”.
  4. Follow the steps in the installation wizard.
    安装完成
    在这里插入图片描述

在这里给出你的GitHub Lab2仓库的URL地址(Lab2-学号)。
https://github.com/ComputerScienceHIT/HIT-Lab2-1190202002

3实验过程

3.1Poetic Walks

一.先构建一个有向加权图的操作,包括创建图,以及对图中顶点和边的增,删,改,查。
二.复用之前完成的图操作,将一段文本的各个词作为点,各词之间的联系作为边的权。即:此b出现在a后几次,则a到b的边权为几。
三.根据输入语段和完成的文本图,查找文本图中同时出现在输入语段两词a b,a后b前的词。将此词加入a b之间,以此类推,完成对输入语段的扩句。

3.1.1Get the code and prepare Git repository

如何从GitHub获取该任务的代码、在本地创建git仓库、使用git管理本地开发。在 Get the code 步骤中,无法连接 MIT 的 Athena 服务器,将从以下地
址获取初始代码https://github.com/rainywang/Spring2021_HITCS_SC_Lab2/tree/master/P1

git clone https://github.com/rainywang/Spring2021_HITCS_SC_Lab2/tree/master/P1

git init 创建本地空仓库
git add README.md //文件添加到仓库
git add . //不但可以跟单一文件,还可以跟通配符,更可以跟目录。一个点就把当前目录下所有未追踪的文件全部add了
git commit -m “first commit” //把文件提交到仓库
git remote add origin git@github.com:wangjiax9/practice.git //关联远程仓库
git push -u origin master //把本地库的所有内容推送到远程库上

在作业描述中若遇到“commit and push”的要求,请将你的代码 push 到你
的 GitHub Lab2 仓库中。g

3.1.2Problem 1: Test Graph

设计:向GraphStaticTest.java和GraphInstanceTest添加测试。包括对add,set,remove,vertices,sources,targets的测试。
实现:静态 Graph.empty() 方法的测试策略是静态的,因此只有一种实现,我们只需要运行一次这些测试。MIT提供了这些测试。需要为 GraphInstanceTest.java 中的所有实例方法编写测试策略和测试。在这些测试中,必须使用 emptyInstance() 方法来获取新的空图,而不是 Graph.empty()。
过程:testAdd:添加点,测试图中是否包含这些点。
testSet:设置两点之间权值,测试当weight为正数,负数,0时,所得的之前weight的结果是否符合要求。
testRemove:删除点和相连的边,根据删除返回true,没有此点返回false,进行测试返回值与实际是否相同。并在删除后添加此点和相连的边,根据返回值判断是否真的删除。
testVertices:测试生成的点集是否将所有点包含在内。
testSources:测试根据source生成的Hashmap<targets,weights>与我们的判断应该生成的Map是否相同。
testTargets:测试根据target生成的Hashmap<sources,weights>与我们的判断应该生成的Map是否相同。
结果:全部完成后的测试结果,对graph代码覆盖率达到90.5%。
在这里插入图片描述
在这里插入图片描述

3.1.3Problem 2: Implement Graph

设计:实现分为两种,Implement ConcreteEdgesGraph和Implement ConcreteVerticesGraph。无论哪种,最终都需要实现图的add,set,remove,vertices,sources,targets函数。不同的是,对于两种实现,所用到的类和类中的操作不同,第一个用Edge实现,第二个用Vertices实现。导致图的函数实现略有不同。

3.1.3.1Implement ConcreteEdgesGraph

实现:由于是图的边实现,所以需要定义Edge类,在类中有边的出发点,终点,权值。类中应包含返回出发点,终点,权值的函数。然后用由所有Edge组成的列表和包含所有点的元组完成图的实现的各类函数add,set,remove,vertices,sources,targets。
过程:先完成Edge类的实现,边需要在类中定义私有变量出发点source,终点target,权值weight,根据这三个变量的输入构成Edge。
在Edge类中实现返回出发点source,终点target,权值weight的函数,直接返回对应的变量即可。完成toString函数,将边以字符串形式显示出来,直接将出发点source,终点target,权值weight,以source——>weight——>target形式返回。
完成ConcreteEdgesGraph。首先创建一个要放所有点的元组vertices和一个存放Edge的列表edges。
public boolean add(String vertex):如果vertices中不包含添加点,则将点添加到vertices中,返回true。否则返回false。
public int set(L source, L target, int weight):如果weight<0,直接返回,weight不能为负。否则进行边的增,删,改操作。删改都需要将原本的边删除,所以可以先搜索有无相同source和target的边,若有将weight记录下来,将边从列表中删除,此时删除操作已完成。而增和改此时都是加边,由于weight=0是删除操作,当weight>0直接将边加入列表中并用add操作将点加入即可。返回之前记录的weight值,若没有则之前没有此边,返回的即为0。
public boolean remove(L vertex):如果有此点则将它在vertices中删除,并将edges中所有包含此点的边删除,返回true。否则返回false。
public Set vertices():返回vertices的元组即可
public Map<L, Integer> sources(L target):根据参数target,找到edges中所有包含target的边,将边的source和weight加到map中,返回这个map。
public Map<L, Integer> targets(L source):根据参数source,找到edges中所有包含source的边,将边的target和weight加到map中,返回这个map。
public String toString():遍历所有边,将所有边的toString生成的字符串连在一起,输出。
结果:对ConcreteEdgesGraph进行测试,全部通过,覆盖率达92.4%
在这里插入图片描述在这里插入图片描述

3.1.3.2Implement ConcreteVerticesGraph

实现:由于是图的点实现,所以需要定义Vertex类,在类中有一个点以及从这个点出发连向的所有点和权值组成的map。类中应包含返回出发点,终点和权值map的函数。然后用由所有Vertex组成的列表完成图的实现的各类函数add,set,remove,vertices,sources,targets。
过程:先完成Vertex类的实现,点在类中定义为私有变量出发点source,target和weight组成map,根据这两个变量构成Vertex。
在Vertex类中实现返回出发点source,终点target和权值weight组成的map函数,直接返回对应的变量即可。完成toString函数,以字符串形式显示出来,直接将出发点source,map中的终点targets,权值weights,以source——>weight——>target形式返回。
完成 ConcreteVerticesGraph。首先创建一个要放所有点Vertex的列表vertices。
public boolean add(String vertex):如果vertices中的每个Vertex中的source都不是添加点,则构建一个Vertex,将vertex作为source,将Vertex添加到vertices中,返回true。否则返回false。
public int set(L source, L target, int weight):如果weight<0,直接返回,weight不能为负。否则进行边的增,删,改操作。删改都需要将原本的边删除,所以可以先搜索有无相同source的Vertex,Vertex中的map中有无target,若有将weight记录下来,在map中将key=target删除,此时删除操作已完成。而增和改此时都是加边,由于weight=0是删除操作,当weight>0用add操作将点加入vertices,搜索对应的source,在map中加入key=target,value=weight。返回之前记录的weight值,若没有则之前没有此边,返回的即为0。
public boolean remove(L vertex):搜索此点,如果此点为Vertex中source,则删掉此Vertex;若此点为map中的key,则将map中此key删除。返回true。否则返回false。
public Set vertices():将vertices中所有Vertex的source放入一个元组中,返回。
public Map<L, Integer> sources(L target):根据参数target,搜索vertices找到Vertex中对应的source和map中的value将source和value加到map中,返回这个map。
public Map<L, Integer> targets(L source):根据参数source,搜索vertices找到相同source的Vertex,返回targetmap即可。
public String toString():遍历所有Vertex,将所有的toString生成的字符串连在一起,输出。
结果:运行测试通过,覆盖率88.8%。
在这里插入图片描述
在这里插入图片描述

3.1.4Problem 3: Implement generic Graph

设计:进行修改扩充,使得点的类型可以为任意类型。由于基本实现已经完成,所以此处实现比较简单。

3.1.4.1Make the implementations generic

实现:按给出的例子,进行修改,将点类型String改为L。
在这里插入图片描述

过程:Edge 或 List 等类型的变量需要成为 Edge 和 List<Edge>。
类似地像 new ConcreteEdgesGraph() 或 new Edge() 这样的构造函数将需要变为 new ConcreteEdgesGraph() 和 new Edge()

结果:测试仍可通过,graph的覆盖率达到90.5%
在这里插入图片描述

3.1.4.2Implement Graph.empty()

实现:在Graph.empty中直接返回一个新的ConcreteEdgesGraph。
在这里插入图片描述

增加GraphStaticTest.java中对其他标签类型的测试,较为简单,不做过多描述
在这里插入图片描述

结果:测试仍可通过,graph的覆盖率达到90.5%
在这里插入图片描述

3.1.5Problem 4: Poetic walks

设计:复用之前完成的图操作,将一段文本的各个词作为点,各词之间的联系作为边的权。即:此b出现在a后几次,则a到b的边权为几。根据输入语段和完成的文本图,查找文本图中同时出现在输入语段两词a b,a后b前的词。将此词加入a b之间,以此类推,完成对输入语段的扩句

3.1.5.1Test GraphPoet

实现:测试应使用一个或多个示例语料库文件。将语料文件1.txt放在 test/P1/poet中。
过程:内容为From time to time,sadness fills my throat and pain.测试当输入语句为From time to sadness时,生成的语句是否为From time to time sadness。

3.1.5.2Implement GraphPoet

实现:定义一个之前实现的空图。将文本语料进行空格和符号的分词,分成一个个单词。从前到后读取两个相连的单词,通过pre_weight=graph.set(words[i].toLowerCase(), words[i+1].toLowerCase(), 0);会将图中已经存在的权值返回记录到pre_weight中,并将已经存在的删除。再通过graph.set(words[i].toLowerCase(), words[i+1].toLowerCase(), pre_weight+1);将新的权值记录下来。而若不存在,因pre_weight初始值赋为0,再加1刚好对应当前权值。
过程:
在这里插入图片描述

结果:生成了一个关于语料文件的可以反映词之间关系的图。

3.1.5.3Graph poetry slam

实现:将输入语句分为一个个单词,从前到后读取连续的两个单词,前面的作为source,后面的作为target,source通过graph.targets获取目标点map,target通过graph.sources获取出发点map。寻找两个map中的相同key的词,如果有将此key在两个map中的value的和相加,将结果最大的那个key加入source,target之间,扩充。如果没有,则不扩充,继续向后找。
过程:
在这里插入图片描述

结果:生成结果正确,测试通过
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.1.6Before you’re done

已进行检查,均已完成。
请按照http://web.mit.edu/6.031/www/sp17/psets/ps2/#before_youre_done的说明,检查你的程序。
如何通过Git提交当前版本到GitHub上你的Lab2仓库。
git commit -a -m “no1”
git remote add origin git@github.com/ComputerScienceHIT/HIT-Lab2-1190202002.git
git pull --rebase origin master
git push -u origin master

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

3.2Re-implement the Social Network in Lab1

基于 3.1 节 Poetic Walks 中定义的 Graph及其两种 实现,重新实现 Lab1 中 3.3 节的 FriendshipGraph 类。
注 1:可以忽略你在 Lab1 中实现的代码,无需其基础上实现本次作业;
注 2:在本节 FriendshipGraph 中,图中的节点仍需为 Person 类型。故你的新 FriendshipGraph 类要利用 3.1 节已经实现的 ConcreteEdgesGraph 或 ConcreteVerticesGraph,L 替换为 Person。根据 Lab1 的要求, FriendshipGraph 中应提供 addVertex()、addEdge()和 getDistance()三个方法 : 针对 addVertex() 和 addEdge() ,你需要尽可能复用 ConcreteEdgesGraph或 ConcreteVerticesGraph中已经实现的 add() 和 set()方法,而不是从 0 开始写代码实现或者把你的 Lab1 相关代码直接复制过来;针对 getDistance()方法,请基于你所选定的 ConcreteEdgesGraph 或 ConcreteVerticesGraph的 rep 来实现,而不能修改其 rep。
注 3:不变动 Lab1 的 3.3 节给出的客户端代码(例如 main()中的代码),即
同样的客户端代码仍可运行。重新执行你在 Lab1 里所写的 JUnit 测试用例,测试你在本实验里新实现的 FriendshipGraph 类仍然表现正常。

3.2.1FriendshipGraph类

思路:FriendshipGraph类有三个功能:添加成员addVertex,增加有向边addEdge,计算两个人相连的最短距离getDistance(自己和自己距离为0,无法相连输出-1),以及返回生成图verticesGraph。
过程:addVertex:调用graph.add()直接添加。
addEdge:调用graph.set()进行设置边。
getDistance:采用先广搜索,构建一个队列,并构建一个HashMap<Person, Integer> map。将出发点的人添加到队列,添加到map的Key处,0加到Value处,读取队首,poll队首,读取他的每个朋友,若其朋友不在map中,则将其朋友全部添加到队列,并map.put(朋友,队首人的value+1),如果队列不空则一直循环,在循环中如果找到了终止点的人,则返回这个人在map中对应value值,即为距离。否则返回-1。
示意如下图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

结果:
添加成员addVertex。
增加有向边addEdge。
getDistance输出两个人相连的最短距离,自己和自己距离为0,无法相连输出-1。

3.2.2Person类

思路:建立Person类,由于各功能都能用图来实现,所以此时无需定义任何操作,只建立Person类即可。

3.2.3客户端main()

实验要求中已经给出,不做过多赘述。就进行了创建人员,添加人员,建立朋友关系,输出距离。
在这里插入图片描述

3.2.4测试用例

思路:测试用例可仿照3.3.3中给出的进行设计。创建人员,添加人员,建立朋友关系,输出距离。并进行断言。
过程:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.2.5提交至Git仓库

如何通过Git提交当前版本到GitHub上你的Lab3仓库。
git commit -a -m “no2”
git remote add origin git@github.com/ComputerScienceHIT/HIT-Lab2-1190202002.git
git pull --rebase origin master
git push -u origin master

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

4实验进度记录

日期 时间段 计划任务 实际完成情况
2021.6.6 20:00-23:00 将P1中graph完成 只完成了graph中的边实现
2021.6.10 12:00-22:00 将代码全部写完 完成
2021.6.11 14:00-20:00 将实验报告完成 完成

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

遇到的难点 解决途径
在点实现的过程中,对点类的构造错误,导致后续无法完成对应的图的实现 在点类中添加对应的相连的点与权值构成的map
在循环中如果将循环到的删除,会导致循环错误,无法继续进行

改用迭代器iterator进行遍历删除操作。

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

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

要充分利用好已经完成的程序,做好复用能大大提升工作效率,并减少代码量。设计好实验测试,用Coverage进行测试,查看未覆盖代码的问题。

6.2针对以下方面的感受

(1)面向ADT的编程和直接面向应用场景编程,你体会到二者有何差异?
面向ADT编程,能很好地进行复用,更安全、结构性更好。面向场景编程,更加直观。
(2)使用泛型和不使用泛型的编程,对你来说有何差异?
泛型更加灵活,适用的情况更多。
(3)在给出ADT的规约后就开始编写测试用例,优势是什么?你是否能够适应这种测试方式?
随时进行测试,保证正确性。感觉很好,但不太适应。
(4)P1设计的ADT在多个应用场景下使用,这种复用带来什么好处?
减少工作量和代码量,而且复用能保证正确性和安全性。
(5)为ADT撰写specification, invariants, RI, AF,时刻注意ADT是否有rep exposure,这些工作的意义是什么?你是否愿意在以后编程中坚持这么做?
保证ADT的正确和安全,减少出现问题的可能,愿意。
(6)关于本实验的工作量、难度、deadline。
工作量很大,难度对于初学者很高,不过给出的时间也很长,还是能够完成。
(7)《软件构造》课程进展到目前,你对该课程有何体会和建议?
对于面向对象有了更深刻的认识,感觉这门课主要学习的是Java的思想。

这篇关于2021年春季学期计算学部《软件构造》课程Lab 2实验报告的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/561792

相关文章

poj 1113 凸包+简单几何计算

题意: 给N个平面上的点,现在要在离点外L米处建城墙,使得城墙把所有点都包含进去且城墙的长度最短。 解析: 韬哥出的某次训练赛上A出的第一道计算几何,算是大水题吧。 用convexhull算法把凸包求出来,然后加加减减就A了。 计算见下图: 好久没玩画图了啊好开心。 代码: #include <iostream>#include <cstdio>#inclu

uva 1342 欧拉定理(计算几何模板)

题意: 给几个点,把这几个点用直线连起来,求这些直线把平面分成了几个。 解析: 欧拉定理: 顶点数 + 面数 - 边数= 2。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#inc

uva 11178 计算集合模板题

题意: 求三角形行三个角三等分点射线交出的内三角形坐标。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <

软件设计师备考——计算机系统

学习内容源自「软件设计师」 上午题 #1 计算机系统_哔哩哔哩_bilibili 目录 1.1.1 计算机系统硬件基本组成 1.1.2 中央处理单元 1.CPU 的功能 1)运算器 2)控制器 RISC && CISC 流水线控制 存储器  Cache 中断 输入输出IO控制方式 程序查询方式 中断驱动方式 直接存储器方式(DMA)  ​编辑 总线 ​编辑

XTU 1237 计算几何

题面: Magic Triangle Problem Description: Huangriq is a respectful acmer in ACM team of XTU because he brought the best place in regional contest in history of XTU. Huangriq works in a big compa

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

免费也能高质量!2024年免费录屏软件深度对比评测

我公司因为客户覆盖面广的原因经常会开远程会议,有时候说的内容比较广需要引用多份的数据,我记录起来有一定难度,所以一般都用录屏工具来记录会议内容。这次我们来一起探索有什么免费录屏工具可以提高我们的工作效率吧。 1.福晰录屏大师 链接直达:https://www.foxitsoftware.cn/REC/  录屏软件录屏功能就是本职,这款录屏工具在录屏模式上提供了多种选项,可以选择屏幕录制、窗口

leetcode105 从前序与中序遍历序列构造二叉树

根据一棵树的前序遍历与中序遍历构造二叉树。 注意: 你可以假设树中没有重复的元素。 例如,给出 前序遍历 preorder = [3,9,20,15,7]中序遍历 inorder = [9,3,15,20,7] 返回如下的二叉树: 3/ \9 20/ \15 7   class Solution {public TreeNode buildTree(int[] pr

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显

HomeBank:开源免费的个人财务管理软件

在个人财务管理领域,找到一个既免费又开源的解决方案并非易事。HomeBank&nbsp;正是这样一个项目,它不仅提供了强大的功能,还拥有一个活跃的社区,不断推动其发展和完善。 开源免费:HomeBank 是一个完全开源的项目,用户可以自由地使用、修改和分发。用户友好的界面:提供直观的图形用户界面,使得非技术用户也能轻松上手。数据导入支持:支持从 Quicken、Microsoft Money