欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

软件构造Lab2

程序员文章站 2022-03-10 14:52:50
...

2020年春季学期
计算机学院《软件构造》课程

Lab 2实验报告

姓名 聂兆彦
学号 1180300429
班号 1803401
电子邮件 [email protected]
手机号码 15504871876

目录

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 1
3.1.3 Problem 2: Implement Graph 1
3.1.3.1 Implement ConcreteEdgesGraph 2
3.1.3.2 Implement ConcreteVerticesGraph 2
3.1.4 Problem 3: Implement generic Graph 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 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
3.3 Playing Chess 3
3.3.1 ADT设计/实现方案 3
3.3.2 主程序MyChessAndGoGame设计/实现方案 3
3.3.3 ADT和主程序的测试方案 3
4 实验进度记录 4
5 实验过程中遇到的困难与解决途径 4
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实验环境配置

在Help里面的install new software里面输入EclEmma的名称网址,安装后重启
新出现这个图标后安装成功

https://github.com/ComputerScienceHIT/Lab2-1180300501.git
3实验过程
3.1Poetic Walks
首先是需要构造一个Graph来实现所需要的功能,然后以边和点两种方式来实现接口,并且需要将ADT泛型化。
然后构造poem,再由input和图中的关系,得出poem。
3.1.1Get the code and prepare Git repository
如何从GitHub获取该任务的代码、在本地创建git仓库、使用git管理本地开发。
创建本地仓库,并且将所需要的代码从GitHub上fork下来
git init
git remote add origin


git clone
3.1.2Problem 1: Test Graph
选用ConcreteEdgesGraph 作为Graph的实现,如果需要测试,则将Graph里面将empty()修改为如下:

此时运行GraphStaticTest可以得到测试结果:

3.1.3Problem 2: Implement Graph
以下各部分,请按照MIT页面上相应部分的要求,逐项列出你的设计和实现思路/过程/结果。
3.1.3.1Implement ConcreteEdgesGraph
// Abstraction function:
// graph中边和点的抽象
// 边的类包括一条带权值的边:从tail到head,权值是weight,构成有向图
// Representation invariant:
// 包含一个隐藏的数学不变式:n个点最多有n*(n-1)/2个边
// Safety from rep exposure:
// 所有的字段都定义为private final 类型
// 顶点和边是immutable类型
// 包含防御式拷贝

//  constructor
public ConcreteEdgesGraph() {
	checkRep();

}

//  checkRep 

// 检测表示不变性,即上面提到的隐藏数学不变式

//增加一个顶点,返回一个boolean类型,判断是否添加成功
public boolean add(String vertex)

//找到相对应的顶点并且返回之前的权值
//如果weight是正数,没有找到顶点时候添加顶点和边,找到了则更新这条边
public int set(String source, String target, int weight)

//移除一个顶点,并且返回是否移除成功的一个boolean值
public boolean remove(String vertex)

//返回顶点,并且用哈希集合来表示
public Set vertices()

//返回source,即带权值的边的尾部
public Map<String, Integer> sources(String target)

//返回target,即带权值边的头部
public Map<String, Integer> targets(String source)

//表达边,如果图是空的,则返回Empty Graph
public String toString()

在类Class中包含:
// 字段包括边的头、尾、和权值
private final String tail;
private final String head;
private final int weight;

方法包括检查权值是否大于0的CheckRep,head(),tail(),weight(),toString()
测试类的思路:测试是否为空的情况,测试表达为String,测试边的情况
3.1.3.2Implement ConcreteVerticesGraph
// Abstraction function:
// 将加权图表述为顶点
// 加权图的边用顶点之间的映射关系来描述
// 顶点包含权值weight
// Representation invariant:
// 顶点个数和vertices()相等
// Safety from rep exposure:
// 变量定义为private final
// 防御式编程

//  constructor
public ConcreteVerticesGraph() {
	checkRep();
}

//  checkRep
private void checkRep() {
	assert vertices().size() == vertices.size();
}

//如果vertices中已经包含vertex,则返回false,否则增加一个顶点
@Override public boolean add(String vertex)

//如果vertices()中包含source,则返回它的下标index,否则创造一个新的点,对target也是如此
@Override public int set(String source, String target, int weight)

//如果vertices()中不包含vertex,则返回false,否则遍历所有的点,删除映射关系并且删除点
@Override public boolean remove(String vertex)

//返回所有点对应的String
@Override public Set<String> vertices()

//返回sources
@Override public Map<String, Integer> sources(String target)

//返回targets
@Override public Map<String, Integer> targets(String source)

//toString()
@Override public String toString()
// 字段包括代表点的String类型的标签,和所有的sources和targets
private final String label;
private final Map<String, Integer> sources = new HashMap<>();
private final Map<String, Integer> targets = new HashMap<>();
    // Abstraction function:
//   顶点类刻画图
//   使用HashMap来存储映射关系 key为source或者target, value为weight
// Representation invariant:
//   每个顶点的target和source不能是自己
// Safety from rep exposure:
//   所有的字段是private final类型
//   HashMap中的Value不能为0
//   输入不能为空,也不能是这个点本身

// constructor
public Vertex(final String label) {
	this.label = label;
}	

//CheckRep 检查上述的RI

//返回label
public String getLabel()
//增加Source
public boolean addSource(final String source, final int weight)
//增加Target
public boolean addTarget(final String target, final int weight)
//移除Source以及映射关系
public int removeSource(final String source)
//移除Target和映射关系
public int removeTarget(final String target)
//移除某个点
public int remove(final String vertex)
//设置Source值返回之前的weight
public int setSource(final String source, final int weight)
//设置Target值返回之前的weight
public int setTarget(final String target, final int weight)
//返回Sources
public Map<String, Integer> getSources()
//返回Targets
public Map<String, Integer> getTargets()
//判断是否是Source
public boolean isSource(final String vertex)
//判断是否是Target
public boolean isTarget(final String vertex)

3.1.4Problem 3: Implement generic Graph
3.1.4.1Make the implementations generic
将具体的声明变量更改为
public
class ConcreteEdgesGraph implements Graph
使用占位符L代替String

3.1.4.2Implement Graph.empty()
选择ConcreteEdgesGraph来使用和实施Graph.empty();
3.1.5Problem 4: Poetic walks
3.1.5.1Test GraphPoet
给一个输出input,在调用poet之后观察输出是否和预期的相等
3.1.5.2Implement GraphPoet
// Abstraction function:
// 将输入的文本单词提取为顶点构建有向图并转化为poem
// Representation invariant:
// 有向图不为空
// Safety from rep exposure:
// 所有的变量都是private final
// 防御式编程

//先从词库的图形中创建一个新的poet,读取文件并且将单词存在words中,读取文件
//然后调用Graph中的类的方法,将单词转化为图,添加顶点并且设置权值为1
public GraphPoet(File corpus) throws IOException

//遍历input中的所有词语,调用Graph中的tragets和sources的方法。如果第一个词语的targets
//和第二词语的sources有交集,则添加bridge,并且在两个单词中的bridges中选择一个插入
public String poem(String input)

3.1.5.3Graph poetry slam
3.1.6Before you’re done
请按照http://web.mit.edu/6.031/www/sp17/psets/ps2/#before_youre_done的说明,检查你的程序。
如何通过Git提交当前版本到GitHub上你的Lab2仓库。
git add Lab2-1180300429
git commit
git push origin master
在这里给出你的项目的目录结构树状示意图。

3.2Re-implement the Social Network in Lab1
这个实验是基于Poetic Walks中定义的Graph,重新实现Lab1中的FriendShipGraph类。尽可能复用ConcreteEdgesGraph中已经实现的add()和set()方法,并且不修改父类的rep
3.2.1FriendshipGraph类
public void addVertex(Person p)
直接调用父类的add可以实现。this.add§
Public void addEdge(Person p1, Person p2)
直接调用父类中的set可以实现

Public int getDistance(Person p1, Person p2)
运行结果:

3.2.2Person类
Person类相对于之前的没有什么变化,同时还需要一个Queue类
3.2.3客户端main()
先new一个FriendshipGraph类的对象,然后添加顶点和边
3.2.4测试用例
3.2.5提交至Git仓库
如何通过Git提交当前版本到GitHub上你的Lab3仓库。
git add Lab2-1180300501
git commit -m “第二次提交”
git push origin master
在这里给出你的项目的目录结构树状示意图。
Src:

Test:

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

看不懂题目的意思
请教同学

对于泛型类L的定义不清楚
网上查询

对于继承的机制不清楚
网上查询
5实验过程中收获的经验、教训、感想
5.1实验过程中收获的经验和教训
5.2针对以下方面的感受
(1)面向ADT的编程和直接面向应用场景编程,你体会到二者有何差异?
利用ADT可以很好的完成抽象化,能够解决一类的应用场景
(2)使用泛型和不使用泛型的编程,对你来说有何差异?
编程方面差异不会特别大,但是应用方面会很广
(3)在给出ADT的规约后就开始编写测试用例,优势是什么?你是否能够适应这种测试方式?
优势在于可以在设计的时候就进行测试,有助于编程的检查
现在并没有适应这种方式,在编写P1的时候是先完成功能再编写测试的
(4)P1设计的ADT在多个应用场景下使用,这种复用带来什么好处?
免去大量的重复性代码的编写
(5)P3要求你从0开始设计ADT并使用它们完成一个具体应用,你是否已适应从具体应用场景到ADT的“抽象映射”?相比起P1给出了ADT非常明确的rep和方法、ADT之间的逻辑关系,P3要求你自主设计这些内容,你的感受如何?
没有完成P3
(6)为ADT撰写specification, invariants, RI, AF,时刻注意ADT是否有rep exposure,这些工作的意义是什么?你是否愿意在以后编程中坚持这么做?
意义在于明确设计的ADT接口和使用规范,方便别人和自己在别处复用ADT,以后的编程中也需要撰写这些项目
(7)关于本实验的工作量、难度、deadline。
DDL合适,难度我感觉对于会写的人来说应该不会很大,工作量同理,同时设计的每一个任务都有明确的目的和递进关系
但是由于在家学习的原因,在完成LAB1之后很长一段时间没有缓过状态,直到最后几天才开始写代码,又花了很长的时间去理解任务的要求,在这个过程感到烦躁。后来发现如果加深JAVA的理解和能够耐心的阅读文档,这次任务应该不会很艰难。
(8)《软件构造》课程进展到目前,你对该课程有何体会和建议?
课程进度略微落后于实验进度,我认为可以推迟一下实验的时间。