HIT2022春软件构造实验2

 

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

Lab 2实验报告

姓名

学号

班号

电子邮件

手机号码

目录

1 实验目标概述 1

2 实验环境配置 1

3 实验过程 1

3.1 Poetic Walks 1

3.1.1 Get the code and prepare Git repository 1

3.1.2 Problem 1: Test Graph <String> 1

3.1.3 Problem 2: Implement Graph <String> 1

3.1.3.1 Implement ConcreteEdgesGraph 2

3.1.3.2 Implement ConcreteVerticesGraph 2

3.1.4 Problem 3: Implement generic Graph<L> 2

3.1.4.1 Make the implementations generic 2

3.1.4.2 Implement Graph.empty() 2

3.1.5 Problem 4: Poetic walks 2

3.1.5.1 Test GraphPoet 2

3.1.5.2 Implement GraphPoet 2

3.1.5.3 Graph poetry slam 2

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

3.1.7 Before you’re done 2

3.2 Re-implement the Social Network in Lab1 2

3.2.1 FriendshipGraph 2

3.2.2 Person 3

3.2.3 客户端main() 3

3.2.4 测试用例 3

3.2.5 提交至Git仓库 3

4 实验进度记录 3

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

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

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

6.2 针对以下方面的感受 4

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.实验环境配置

在官网下载了java的jdk,IDEA以及Git。并在IDEA中安装配置了JUnit。

实验需要Eclipse IDE 中安装配置 EclEmma(一个用于统计 JUnit 测试用例的代码覆盖度的 plugin)。在IDEA中自带测试代码覆盖度的功能。可以在test类点击Run with Coverage,就能实现这个功能。

给出我的的GitHub Lab2仓库的URL地址(Lab2-学号)。

https://github.com/ComputerScienceHIT/HIT-Lab2-120L020212

3.实验过程

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

3.1Poetic Walks

在这里简要概述你对该任务的理解。

目的是练习设计、测试和实现ADT。

我们将要实现的类型是Graph<L>,这是一种抽象数据类型,用于带有标记顶点的可变加权有向图。

其中有:

  1. 可变图:顶点和边可以添加到图中,也可以从图中删除
  2. 有向边:边从源顶点到目标顶点
  3. 加权边:边与正整数权重相关联
  4. 标记的顶点:顶点由某些不可变类型的标签区分。

在最后实现GraphPoet,一个使用单词关联图生成诗歌的类。

3.1.1 Get the code and prepare Git repository

如何从GitHub获取该任务的代码、在本地创建git仓库、使用git管理本地开发。

使用git clone指令获取代码。

建立一个目录,通过git init命令就可以把这个目录变成git管理的仓库。

通过各种git命令就可以管理本地开发了。

​​​​​​​3.1.2 Problem 1: Test Graph <String>

以下各部分,请按照MIT页面上相应部分的要求,逐项列出你的设计和实现思路/过程/结果。

首先修改Graph.empty()和vertices方法。

 

测试运行成功。

 

 

GraphInstanceTest测试用例:

除其本身自带的testAssertionsEnabled(测试assert是否可用)
testInitialVerticesEmpty(测试初始时,点集是否为空)

  1. testAdd:测试加入点的功能。
  2. testSet:测试添加、修改删除边权的功能。
  3. testRemove:测试删除点集合中的点的功能。
  4. testVertices:测试返回点集合的功能。
  5. testSources:测试指向某点的点集合以及边权的功能。
  6. testTargets:测试某点指向的点集合以及边权的功能。

具体实现看代码。

​​​​​​​3.1.3 Problem 2: Implement Graph <String>

以下各部分,请按照MIT页面上相应部分的要求,逐项列出你的设计和实现思路/过程/结果。3.1.3.1 Implement ConcreteEdgesGraph

Edge类:

private int weight;//边的权重

private L source;//起点

private L target;//终点

public Edge(L source, L target, int weight):增加一个edge

方法:

public void setweight(int weight):改变weight

public L source():返回source

public L target():返回target

public int weight():返回weight

//toString()

public String toString():返回字符串表示的edge,自动生成的就行

ConcreteEdgesGraph类:

protected final Set<L> vertices = new HashSet<>();//存储所有顶点

private final List<Edge<L>> edges = new ArrayList<>();//存储所有边

方法:

public boolean add(L vertex):增加一个顶点

public int findedge(L source, L target):找到边在list中的位置,返回一个index

public int set(L source, L target, int weight):增加一条有向边

public boolean remove(L vertex):移除一个顶点

public Set<L> vertices():返回包含所有顶点的集合

public Map<L, Integer> sources(L target):返回某个顶点为终点的所有边

public Map<L, Integer> targets(L source):返回某个顶点为起点的所有边

​​​​​​​3.1.3.2 Implement ConcreteVerticesGraph

Vertex类:

private L name;//顶点的名字

private Map<L, Integer> allsource = new HashMap<>();//返回该顶点为起点的所有边

private Map<L, Integer> alltarget = new HashMap<>();//返回该顶点为终点的所有边

public Vertex(L name):增加一个vertex

方法:

public L name():返回顶点名字

public Map<L, Integer> getsource():返回allsource

public Map<L, Integer> gettarget():返回alltarget

public void setsource(L source, int weight):在allsource中增加一个映射

public void settarget(L target, int weight):alltarget中增加一个映射

//toString()

public String toString():自动生成

ConcreteVerticesGraph:

private final List<Vertex<L>> vertices = new ArrayList<>();//储存所有顶点

方法:

public L name():返回顶点名字

public Map<L, Integer> getsource():返回allsource

public Map<L, Integer> gettarget():返回alltarget

public void setsource(L source, int weight):在allsource中增加一个映射

public void settarget(L target, int weight):alltarget中增加一个映射

3.1.4 Problem 3: Implement generic Graph<L>

3.1.4.1 Make the implementations generic

在工具栏->编辑->查找/替换…中将ConcreteEdgesGraph类和ConcreteVerticesGraph类的所有String替换为L,注意toString方法的返回值依旧为String;但是测试用例中依旧是String不变

​​​​​​​3.1.4.2 Implement Graph.empty()

在Graph中找到empty方法,它需要一个实例类,我选择的是 ConcreteEdgesGraph类(Edges和Vertexs选哪个无所谓),对里面的类型进行参数化后(在类型后面加上),还需要再方法声明的static后面也加上(因为不能对非静态类型 L 进行静态引用)

 3.1.5 Problem 4: Poetic walks

 3.1.5.1 Test GraphPoet

 

 3.1.5.2 Implement GraphPoet

private final Graph<String> graph = Graph.empty();

方法:

public GraphPoet(File corpus) throws IOException():corpus中读取原文,处理后存在graph中。

public String poem(String input): public String poem(String input):基于graphinput改为诗歌并返回。

​​​​​​​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仓库。

git add .

git commit

git push

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

 

 3.2 Re-implement the Social Network in Lab1

在这里简要概述你对该任务的理解。

利用上节已经实现的ConcreteEdgesGraph<L>或ConcreteVerticesGraph<L> 替换为 Person。并在FriendshipGraph 中提供 addVertex()、addEdge()和 getDistance()三 个方法 :

针对 addVertex()和 addEdge() ,你需要尽可能复用ConcreteEdgesGraph或 ConcreteVerticesGraph中已经实现的add()和set()方法。针对getDistance()方法,基于所选定的 ConcreteEdgesGraph 或ConcreteVerticesGraph的 rep 来实现,而不能修改其 rep。

要求不变动 Lab1 的 3.3 节给出的客户端代码(例如 main()中的代码),即同样的客户端代码仍可运行。重新执行Lab1里所写的JUnit测试用例,并测试在本实验里新实现的 FriendshipGraph 类仍然要表现正常。

3.2.1 FriendshipGraph

给出你的设计和实现思路/过程/结果。

private final Graph<Person> graph = Graph.empty();

方法:

public boolean addVertex(Person person):增加一个人到关系网中

public boolean addEdge(Person source, Person target, int weight):在关系网中增加一个关系

public int getDistance(Person a, Person b):获取关系网中两个人的距离,使用BFS

​​​​​​​3.2.2 Person

给出你的设计和实现思路/过程/结果。

private  String name;//人的名字

public  int distance;//方便BFS而设置的距离

public Person(String name):增加一个人

方法:

public String name():返回name

public int distance():返回distance

​​​​​​​3.2.3 客户端main()

给出你的设计和实现思路/过程/结果。

使用原Lab1的main函数。

 3.2.4 测试用例

给出你的设计和实现思路/过程/结果。

也是使用原Lab1的测试用例。

 

测试结果

 

覆盖率

 

 3.2.5 提交至Git仓库

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

git add .

git commit

git push

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

 

 4. 实验进度记录

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

每次结束编程时,请向该表格中增加一行。不要事后胡乱填写。

不要嫌烦,该表格可帮助你汇总你在每个任务上付出的时间和精力,发现自己不擅长的任务,后续有意识的弥补。

日期

时间段

计划任务

实际完成情况

2022/5/27

14:00-17:00

完成P1

未完成,GraphPoet尚未完成

2022/5/28

19:00-20:00

完成GraphPoet

完成

2022/5/29

18:30-20-15

完成P2

完成

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

遇到的难点

解决途径

对泛型类不太熟悉

上网查阅相关知识

英文翻译吃力

使用百度翻译帮助理解

P2中的getDistance函数出错,返回的全是-1

发现是没有对遍历的代码进行修改,需要调用vertices()方法

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

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

Java的功能强大,但各种类型细分太多,有些使用不来,其中类似泛型等的理解也需要下一定的苦功夫。

6.2 针对以下方面的感受

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

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

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

使用泛型能够将自己的ADT适用于更加多的情况中,比如图的顶点的名字可以是字符串、可以是整型、也可以是浮点数,扩大了应用的范围,但是泛型化过程中会有一定的难度,比如有时候会出现令人困惑的黄色下划线警告

(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,这些工作的意义是什么?你是否愿意在以后编程中坚持这么做?

提升可维护性,可读性,安全性。因为不能确保ADT一写完以后就不会添加新的功能,提前发现错误,避免数据外泄,愿意。

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

工作量比较大,难度高。时间紧凑。且与考试时间冲突。

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

难度很高,希望在学这门课前学校能先开一门Java语言课。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值