目录
1 实验目标概述··· 1
2 实验环境配置··· 1
3 实验过程··· 1
3.1 Poetic Walks· 2
3.1.1 Get the code and prepare Git repository· 2
3.1.2 Problem 1: Test Graph <String>· 2
3.1.3 Problem 2: Implement Graph <String>· 2
3.1.3.1 Implement ConcreteEdgesGraph· 2
3.1.3.2 Implement ConcreteVerticesGraph· 3
3.1.4 Problem 3: Implement generic Graph<L>· 3
3.1.4.1 Make the implementations generic· 3
3.1.4.2 Implement Graph.empty()· 4
3.1.5 Problem 4: Poetic walks· 4
3.1.5.1 Test GraphPoet· 4
3.1.5.2 Implement GraphPoet· 4
3.1.5.3 Graph poetry slam·· 4
3.1.6 Before you’re done· 4
3.2 Re-implement the Social Network in Lab1· 5
3.2.1 FriendshipGraph类··· 5
3.2.2 Person类··· 5
3.2.3 客户端main()· 6
3.2.4 测试用例··· 6
3.2.5 提交至Git仓库··· 6
3.3 Playing Chess· 6
3.3.1 ADT设计/实现方案··· 6
3.3.2 主程序ChessGame设计/实现方案··· 8
3.3.3 ADT和主程序的测试方案··· 8
3.4 Multi-Startup Set (MIT) 9
4 实验进度记录··· 9
5 实验过程中遇到的困难与解决途径··· 9
6 实验过程中收获的经验、教训、感想··· 9
6.1 实验过程中收获的经验和教训··· 9
6.2 针对以下方面的感受··· 10
1 实验目标概述
本次实验训练抽象数据类型(ADT)的设计、规约、测试,并使用面向对象 编程(OOP)技术实现 ADT。具体来说:
l 针对给定的应用问题,从问题描述中识别所需的 ADT;
l 设计 ADT 规约(pre-condition、post-condition)并评估规约的质量;
l 根据 ADT 的规约设计测试用例;
l ADT 的泛型化;
l 根据规约设计 ADT 的多种不同的实现;
l 针对每种实现,设计其表示 (representation)、表示不变性(rep invariant)、抽象过程(abstraction function)
l 使用 OOP 实现 ADT,并判定表示不变性是否违反、各实现是否存在表 示外泄(rep exposure);
l 测试 ADT 的实现并评估测试的覆盖度;
l 使用 ADT 及其实现,为应用问题开发程序。
2 在测试代码中,能够写出 testing strategy 并据此设计测试用例。
3 实验环境配置
简要陈述你配置本次实验所需环境的过程,必要时可以给出屏幕截图。
特别是要记录配置过程中遇到的问题和困难,以及如何解决的。
暂无
在这里给出你的GitHub Lab2仓库的URL地址(Lab2-学号)。
https://github.com/ComputerScienceHIT/Lab2-1170400307
4 实验过程
请仔细对照实验手册,针对三个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。
4.1 Poetic Walks
该实验要求我们按照MIT上的操作步骤逐步完成自己的第一个泛型Graph<L>的设计和测试,并应用该泛型实现poetic walks功能。
4.1.1 Get the code and prepare Git repository
如何从GitHub获取该任务的代码、在本地创建git仓库、使用git管理本地开发。
从https://github.com/ComputerScienceHIT/Lab2-1170400307获取
4.1.2 Problem 1: Test Graph <String>
如果需要测试,默认ConcreteEdgesGraph implements Graph<String>,修改empty为:
Public Graph<String> empty() {
return new ConcreteEdgesGraph();
}
此时可以运行GraphStaticTest进行测试。
4.1.3 Problem 2: Implement Graph <String>
4.1.3.1 Implement ConcreteEdgesGraph
图类给出的对象有vertices和edges,适用邻接矩阵实现图的功能;
根据MIT上对Graph<L>的各种方法的说明完成各方法的功能;
设计Edge<String>类,类中对象应包含边的起点、终点和权重,为防止rep exposure应都为private final,同时需要实现获取各对象的方法,以便Graph<String>方法的实现;
设计set()方法时设置hasedge值用来记录图中是否已经存在待设置的边,并实现不同情况的功能;
设计toString()方法,使用Collections类的stream()方法和Edge<String>类中设计的toString()方法转化并输出字符串;
设计对Graph<String>和Edge<String>类中的方法的测试策略和测试用例,并保证具有高覆盖度,详见test strategy。
4.1.3.2 Implement ConcreteVerticesGraph
该图类给出的对象只有vertices,适用邻接表实现图的功能;
根据MIT上对Graph<L>的各种方法的说明完成各方法的功能;
设计Vertex<String>类,类中对象应包含顶点名称以及顶点的边表,为防止rep exposure应都为private final,需要实现获取顶点名、判断边表中是否存在指定顶点、设置边权值、输出边表等的方法,以便Graph<String>方法的实现;
设计set()方法,使用Vertex<String>类中设计的hasTarget()方法判断待设置边是否已经存在,以实现不同情况的功能,并使用Vertex<String>类中设计的set()方法设置边权值;
设计toString()方法,使用Collections类的stream()方法和Vertex<String>类中设计的toString()方法转化并输出字符串。
设计对Graph<String>和Vertex<String>类中的方法的测试策略和测试用例,并保证具有高覆盖度,详见test strategy。
4.1.4 Problem 3: Implement generic Graph<L>
4.1.4.1 Make the implementations generic
将3.1.3中的除了toString部分外的String类型的对象都改成L类型。
继承Graph<L>类时,应根据L表示的具体数据类型重写toString()、equals()、hashCode()方法。
4.1.4.2 Implement Graph.empty()
调用Graph.empty()生成ConcreteEdgesGraph或ConcreteVerticesGraph,无论生成的是何种图,用户在进行操作的过程和获得的结果应该都是一致的;
设计L为Integer的功能测试,对两种不同的Graph.empty()进行测试,测试结果应一致且通过。
4.1.5 Problem 4: Poetic walks
4.1.5.1 Test GraphPoet
测试从文件按词获取字符串的功能、poem()方法、以及toString()方法。
4.1.5.2 Implement GraphPoet
设计getWordsFromFile(),使用Scanner类按词读取文件;
设计getCorpusWords(),获取单词表;
设计connectWords(),每两个相邻单词之间形成一条边;
设计poem(),根据输入,查找单词表,若两个单词之间空了一个单词,则插入该单词。使用Gaph类的getTargets()方法实现查找两个单词之间是否空有单词,使用Collections类的 stream().collect()方法输出字符串;
设计toString,按顺序输出单词表。
4.1.5.3 Graph poetry slam
利用压缩包提供的txt文件完成。
4.1.6 Before you’re done
请按照http://web.mit.edu/6.031/www/sp17/psets/ps2/#before_youre_done的说明,检查你的程序。
如何通过Git提交当前版本到GitHub上你的Lab2仓库。
- 用eclipse在本地新建一个项目;
- 在命令行中用“git init”新建库
- 利用git remote add origin <url>将本地库和远程库链接
- 将远程源中master分支的仓库拉到本地git push -u origin maste
- Git add .打包本地项目
- Git commit -m “20190301”为本地文件做标记
- Git push origin master推送上仓库
在这里给出你的项目的目录结构树状示意图。
测试截图如下:
4.2 Re-implement the Social Network in Lab1
该实验要求我们使用前一个问题完成的Graph<L>泛型实现Lab1中的Social Network,只改变结点的类型和部分方法的实现方案,确保功能不变。
4.2.1 FriendshipGraph类
采用的是邻接表的展示结构,效率较高。在List类型内装入Person类型,而且每一个Person内有List存储每一个人的序号
对于求出两个person之间的距离,先调用方法。
这个方法以一个person为起点进行深度优先搜索,标记搜索过的点,并记录距起始搜索点的距离,然后通过getDistance方法获得两个person之间的信息,如果另一个person的distance是0,说明是同一个点,如果未搜索到,说明无关系,返回-1。
4.2.2 Person类
Person设计尽量满足以下几点
1成员变量设置成private,成员变量的访问是通过成员方法进行的
2满足FreindshipGraph的要求
设置对象属性有:personname、isVisit(是否被访问,在getDistance()用到);并且设计getName()方法,输出结点名称。
4.2.3 客户端main()
与Lab1测试用例基本相同,并且在testAddVertex()中对添加重名的顶点进行测试时会遇到system.exit(0)而强行终止程序导致测试不成功,在查阅相关资料后,增加捕捉并屏蔽system.exit(0)发出的信号
4.2.4 测试用例
测试截图:
4.2.5 提交至Git仓库
如何通过Git提交当前版本到GitHub上你的Lab2仓库。
- 用eclipse在本地新建一个项目;
- 在命令行中用“git init”新建库
- 利用git remote add origin <url>将本地库和远程库链接
- 将远程源中master分支的仓库拉到本地git push -u origin maste
- Git add .打包本地项目
- Git commit -m “20190301”为本地文件做标记
- Git push origin master推送上仓库
在这里给出你的项目的目录结构树状示意图。
4.3 Playing Chess
4.3.1 ADT设计/实现方案
- Position类
(1) 各域值的get和set接口函数
(2) 判断两坐标是否相等
- Piece类
(1) 各域值的get和set接口函数
(2) 将棋子移除棋盘
- player类
(1)各域值的get和set接口函数
(2)向玩家类中棋子集合添加新棋子;
(3)获取该玩家所有满足功能函数predicate要求的棋子之中的任意一个;
(4)判断该玩家是否包含指定棋子
(5)向gameHistorySB中添加一步的操作。
- Board类
(1)各域值的get和set接口函数
(2)获取处于(px,py)位置的棋子
(3)将棋子piece放置在棋盘的(px,py)位置处
(4)判断坐标(cx,cy)是否是一个合法坐标
(5)判断棋子piece是否处于棋盘之内。
(6)获得player在棋盘中的棋子数目(也可以将接口交给Player实现)
- action类
(1)各域值的get和set接口函数
(2)将玩家player的未处于棋盘的piece棋子落到pos处。修改棋子piece位置,修改棋盘gameBoard上pos位置的棋子为piece,添加玩家历史。
(3)将玩家player的已经处于棋盘上的位于st的棋子移动到空地址ed。将棋盘上st位置设置为null,ed位置设置为piece,修改piece的位置为ed。添加玩家历史
(4)将用户player的位于棋盘上pos的棋子移出棋盘。调用piece.rmFromBoard,将棋盘上pos位置设置为null。添加玩家历史。
(5)使用用户player的位于棋盘st位置的棋子吃掉到对手的ed位置的棋子。调用edPiece.rmFromBoard,将棋盘ed位置设置为stPiece,将棋盘st位置设置为null,将stPiece坐标设置为ed。添加用户历史。
- game类
(1)各域值的get和set接口函数
(2)通过传入的两个玩家的名字初始化Game中的各类对象。初始化:从gameType_config.txt文件中读取游戏配置,初始化player,添加拥有的棋子,初始化棋盘,设置大小和类型。将gameBoard,playerA,playerB的引用传入Action新建gameAction对象。
(3)获得处于pos位置的棋子的所有者,获得pos位置的棋子piece,然后调用Player.isContainPiece判断属于playerA还是playerB。
(4)获取处于pos位置的棋子piece,如果没有棋子则返回null。
(5)获取用户在棋盘上的所有棋子数目,调用gameBoard. getNumOfPlayerPiecesInBoard
(6)调用ACTION的各接口函数
4.3.2 主程序MyChessAndGoGame设计/实现方案
辅之以执行过程的截图,介绍主程序的设计和实现方案,特别是如何将用户在命令行输入的指令映射到各ADT的具体方法的执行。
(1) 利用while循环,检查边界条件;
(2) 根据命令行分别进入不同的switch选择函数;
(3) 在不同的分支语句中,分别进入不同的GAME接口函数;
(4) GAME中不同的接口函数分别调用不同的类参与运行;
(5) 封装之后主要的类就是棋盘类和玩家类;
(6) 棋子类以及其他类分别依托于棋盘类等工作;
(7) 各个接口函数相互协调、分别工作。
4.3.3 ADT和主程序的测试方案
介绍针对各ADT的各方法的测试方案和testing strategy。
介绍你如何对该应用进行测试用例的设计,以及具体的测试过程。
Chesstest:
(1)测试移动棋子
(2)测试吃子
(3)测试判读棋子归属
(4)测试操作历史记载
Gotest:
(1) 测试下子
(2) 测试提子
(3) 测试判读棋子归属
(4) 测试统计双方棋子数量
测试截图:
4.4 Multi-Startup Set (MIT)
(未进行任务)
5 实验进度记录
请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。
日期 | 时间段 | 计划任务 | 实际完成情况 |
2018.3.24 | 14:00-17:30 | 完成ConcreteEdgesGraph和ConcreteVerticesGraph方法 | 未完成 |
2018.4.1 | 10:00-15:00 | 完成ConcreteEdgesGraph和ConcreteVerticesGraph方法 | 按时完成 |
2018.4.2 | 9:00-12:00 | 完成AF、RI、safety of RE、checkRep | 按时完成 |
2018.4.3 | 8:00-12:00 | 完成toString和testToStrin以及两个图类的测试用例 | 延时完成 |
2018.4.4 | 9:00-12:00 14:00-18:00 | 完成GraphPoet、GraphStaticTest、GraphInstanceTest 、P2, | 按时完成 |
2018.4.7 | 19:00-22:00 | 完成P3 | 按时完成 |
2018.4.8 | 8:30-12:00 | 完成实验报告 | 延时完成 |
6 实验过程中遇到的困难与解决途径
遇到的难点 | 解决途径 |
全英文实验内容造成的理解障碍 | 借助谷歌翻译和询问同学 |
初次使用泛型,不够熟练 | 查阅资料,阅读老师上课内容 |
设计ADT结构无从下手 | 参考同学的思想,网上查阅资料 |
7 实验过程中收获的经验、教训、感想
7.1 实验过程中收获的经验和教训
总体而言,感觉自己对于JAVA编程的技术掌握得更加熟练,遇到问题也可以通过自己上网查询或者阅读书籍解决了。但是距离一名合格的开发人员还有很长的路要走。
7.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,这些工作的意义是什么?你是否愿意在以后编程中坚持这么做?
使得我们代码的健壮性更强;目前不希望。
(7) 关于本实验的工作量、难度、deadline。
工作量偏大,难度较高,希望时间上有所延长。
(8) 《软件构造》课程进展到目前,你对该课程有何体会和建议?
希望自己好好学习,感觉这门课内容很多。