软件构造lab2总结


2021年春季学期
计算学部《软件构造》课程
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。具体来说:
针对给定的应用问题,从问题描述中识别所需的ADT;
设计ADT规约(pre-condition、post-condition)并评估规约的质量;
根据ADT的规约设计测试用例;
ADT的泛型化;
根据规约设计ADT的多种不同的实现;针对每种实现,设计其表示(representation)、表示不变性(rep invariant)、抽象过程(abstraction function)
使用OOP实现ADT,并判定表示不变性是否违反、各实现是否存在表示泄露(rep exposure);
测试ADT的实现并评估测试的覆盖度;
使用ADT及其实现,为应用问题开发程序;
在测试代码中,能够写出testing strategy并据此设计测试用例。

2实验环境配置
在 Eclipse IDE 中安装配置 EclEmma(一个用于统计 JUnit 测试用例的代码覆盖度的 plugin)直接从Eclipse Market下载安装即可。
在这里给出你的GitHub Lab2仓库的URL地址(Lab2-学号)。
https://github.com/ComputerScienceHIT/HIT-Lab2-1190202407
3实验过程
请仔细对照实验手册,针对三个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。
3.1Poetic Walks
该任务是设计一个图模块,实现以下功能
1.完善Graph接口类
2.实现Graph类,完善add、set、remove、sources、targets等
3.利用Graph类,实现GraphPoet类
3.1.1Get the code and prepare Git repository
git init
git remote add origin git@github.com:ComputerScienceHIT /Lab2-1190202407. git pull origin master
git add .
git commit -m “init”
git push origin master
3.1.2Problem 1: Test Graph <String>
测试add,set,remove、sources、targets等函数
add划分输入:vertex:已存入graph的点,未存入的点
set划分输入:source,target:已存入的点,未存入的点
  weight:0,非0
remove划分输入:vertex:已存入,未存入,与其他点相连的点
vertices划分输入:graph:空、非空图
sources划分输入:target:有边连接的点,无边连接的点
target划分输入:source:有边连接的点,无边连接的点  
3.1.3Problem 2: Implement Graph <String>
该部分要求实现Graph Interface里的方法,要求实现ConcreteEdgesGraph与ConcreteVerticesGraph。
3.1.3.1Implement ConcreteEdgesGraph
Edge类设计:
Fields    表示
source    边的起始点
target    边的结束点
weight    边的权值

Methods    作用
Getsource    返回有向边起始节点
Gettarget    返回有向边终结点
Getweight    返回边权值
Tostring    描述边


Concreteedgesgraph类设计:
Fields    用途
Edges    存储顶点
Vertices    存储边


Method    作用
public boolean add(L vertex)    向图中添加一个点
public int set(L source, L target, int weight)    对图进行操作
public boolean remove(L vertex)    从图中移除一个点,及其所关联的边
Public set vertices()    返回图中的点集
public Map<L, Integer> sources(L target)    返回target点所有的入边
public Map<L, Integer> targets(L source)    返回图的string表示

Set设计思路:先判断要添加的边是否已在图中,若起点与终点间权值不为0,则更新权值并返回之前的权值;为0,则删去该边;若不存在,则创建一个新的edge,存储其各信息。

remove的设计思路为:先从点集vertices中删除该点,然后再删除与该点有关的所有边。

3.1.3.2Implement ConcreteVerticesGraph
Vertex类:
Fields    表示
Vertex    当前节点
Outedges    节点的出边
Inedges    节点的入边

Method    作用
Private void checkRep()    检查节点合法性
public Map<L, Integer> sources(L target)    根据传入的target参数寻找以targe为终点的边,返回一个权值对为(点,权重)的map
public Map<L, Integer> targets(L source)    根据传入的source参数寻找以source为起点的边
public boolean remove(L vertex)    删除该节点一条边
public boolean set(L source, L target,int weight)    给当前节点添加一条边

ConcreteVerticeGraph
Method    作用
public boolean add(L vertex)    向图中添加节点
public int set(L source, L target, int weight)    对图进行相关操作
public boolean remove(L vertex)    从图中删除一个点
public Set vertices()    返回图中的点集
public Map<L, Integer> sources(L target)    返回target点的入边
public Map<L, Integer> targets(L source)    返回source点的出边


3.1.4Problem 3: Implement generic Graph<L>
为了使我们的Graph更加地实用,将原本使用String改为使用泛型<L>。
3.1.4.1Make the implementations generic

使用泛型,将原代码中一些原本使用String的地方对应改为泛型的placeholder <L>。
3.1.4.2Implement Graph.empty()

3.1.5Problem 4: Poetic walks
该部分需要我们将前述实现的Graph应用到Poetic walks中,用于将语料库(corpus)转化为Graph,再根据这个Graph将一个输入的String,转换成一个新的String(poem)。
3.1.5.1Test GraphPoet


测试结果:

覆盖率:

3.1.5.2Implement GraphPoet
需要一个类型为String的graph
 
 需要实现的方法
Method    作用
    
    
    

3.1.5.3Graph poetry slam
在给定代码的基础上增加一个toString方法来输出

运行结果:

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

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

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

3.2Re-implement the Social Network in Lab1
继承P1中ConcreteEdgesGraph , ConcreteVerticesGraph类,实现FriendshipGraph,通过基本操作实现FriendshipGraph中addVertex,addEdge和getDistance三个接口。
3.2.1FriendshipGraph类
FriendshipGraph的字段为Person构成的ConcreteEdgesGraph

在FriendshipGraph需要实现的方法如下图所示:
Method    构造方法
addVertex    在图中增加新Person,只需要调用ConcreteEdgesGraph中的add即可
addEdge    为某个人增加朋友,a为这个人,b为其新增的朋友,直接调用ConcreteEdgesGraph中的set即可。
getallfriend     直接返回。
getDistance    得到两个人之间的最短距离,方法与Lab1类似,稍加修改即可:
我们要通过队列,采用广度遍历的思维,把作为起点的人当做p1,终点的人当做p2,先把p1压入队列,然后进入循环,只要队列不为空就不结束循环。还有生成一个叫做len的Map,key的类型是Person,映射到这个人与p1的距离,然后先设一个(p1,0)的映射。接着每次循环一开始都是弹出队列顶部的人,然后把distance基准距离设为这个人在len中映射得到的距离。然后,运用已编写好的方法,生成一个包含这个人所有朋友的集合,遍历这个集合,只要集合中有某人不在len中,就把put到len里,映射的距离是distance+1,同时也把这个人放入队列中。然后,每当一个人的朋友遍历完后,就查看一下len的key中有没有我们要找的p2,如果有,直接返回p2映射到的距离。最后,当最外层的循环结束时,肯定是没有找到p2这个人,那么说明p2与p1间无关系,那么应该返回-1

main    复制Lab1稍作修改。
在FriendshipGraph需要实现的方法如下图所示:
Method    构造方法
addVertex    在图中增加新Person,只需要调用ConcreteEdgesGraph中的add即可。
addEdge    为某个人增加朋友,a为这个人,b为其新增的朋友,直接调用ConcreteEdgesGraph中的set。
getallfriend     直接返回。
getDistance    得到两个人之间的最短距离,方法与Lab1类似,稍加修改。
我们要通过队列,采用广度遍历的思维,把作为起点的人当做p1,终点的人当做p2,先把p1压入队列,然后进入循环,只要队列不为空就不结束循环。还有生成一个叫做len的Map,key的类型是Person,映射到这个人与p1的距离,然后先设一个(p1,0)的映射。接着每次循环一开始都是弹出队列顶部的人,然后把distance基准距离设为这个人在len中映射得到的距离。然后,运用已编写好的方法,生成一个包含这个人所有朋友的集合,遍历这个集合,只要集合中有某人不在len中,就把put到len里,映射的距离是distance+1,同时也把这个人放入队列中。然后,每当一个人的朋友遍历完后,就查看一下len的key中有没有我们要找的p2,如果有,直接返回p2映射到的距离。最后,当最外层的循环结束时,肯定是没有找到p2这个人,那么说明p2与p1间无关系,那么应该返回-1。
main    复制Lab1稍作修改。

3.2.2Person类

Person    没有重复名字则加入,构造方法
getname    返回本人名字
实现方法:

3.2.3客户端main()


运行结果:
    
3.2.4测试用例
测试策略:与Lab1的测试策略相同,先新建一个graph


覆盖率:

3.2.5提交至Git仓库
项目的目录结构:
项目名称:    HIT-Lab2-学号
                src
                        P2
                            FriendshipGraph.java
                            Person.java
                            ...
                    test
                        P2
                            FriendshipGraphTest.java
                            ...

4实验进度记录
请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。
每次结束编程时,请向该表格中增加一行。不要事后胡乱填写。
不要嫌烦,该表格可帮助你汇总你在每个任务上付出的时间和精力,发现自己不擅长的任务,后续有意识的弥补。
日期    时间段    计划任务    实际完成情况
5.31    14:00-17:00    完成P1中concreateedgesgraph和concreteverticesgraph并进行测试    未完成
6.1    15:30-17:30    完成上述任务    完成
6.3    15:45-17:30    完成poetic walks    未完成
6.4    13:00-15:00    继续完成上述任务    完成
6.6    15:00-16:00    完成P2    完成
5实验过程中遇到的困难与解决途径
遇到的难点    解决途径
对于继承类,接口等概念仍不是十分熟悉    通过上网查阅相关资料加以学习
对于poet如何实现增添词时,用于参考的重复的数量,已经增添词的数量该如何确定,如何实现    上网查询并向同学进行咨询
6实验过程中收获的经验、教训、感想
6.1实验过程中收获的经验和教训
更加熟练使用java编写程序,了解规约过程,理解java封装机制。
6.2针对以下方面的感受
(1)面向ADT的编程和直接面向应用场景编程,你体会到二者有何差异?
面向应用场景是直接完成关于类的功能实现的代码,而面向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,这些工作的意义是什么?你是否愿意在以后编程中坚持这么做?
更好的理解ADT;不愿意,太麻烦。
(7)关于本实验的工作量、难度、deadline。
时间比较宽松,难度适中。
(8)《软件构造》课程进展到目前,你对该课程有何体会和建议?
建议有中文的相关学习材料,看英文比较费劲。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值