关于hit软件构造lab2实验后回顾

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)。请访问http://www.eclemma.org,了解EclEmma并学习其安装、配置和使用。

3 实验过程
请仔细对照实验手册,针对三个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。
3.1 Poetic Walks
任务理解:实现图形数据结构。
问题1-3:将实现的类型为Graph ,这是带有标记顶点的可变加权有向图的抽象数据类型。
可变图:可以将顶点和边添加到图中或从图中删除
有向边:边从源顶点到目标顶点
加权边:边与正整数权重关联
标记顶点:顶点通过某种不可变类型的标签来区分,例如,它们可能具有字符串名称或整数ID

在Graph 规范中,我们对类型L的不变性有相同的要求。试图使用可变顶点标签的Graph客户违反了前提条件。 他们不能期望正确的行为
对于此问题集,我们将使用两个不同的代表两次实施Graph,以练习选择抽象函数和rep不变量并防止rep暴露。库有很多充分的理由提供一种类型的多种实现(例如,List的ArrayList和LinkedList实现满足具有不同性能要求的客户端)
问题4:使用我们的图数据类型,我们将实现GraphPoet,这是一个使用单词亲和图生成诗歌的类。
3.1.1 Get the code and prepare Git repository
如何从GitHub获取该任务的代码、在本地创建git仓库、使用git管理本地开发。
从https://github.com/rainywang/Spring2019_HITCS_SC_Lab2/tree/master/P1
中获得dai吗在eclipse建立现目,在完成所有实验后统一进行提交
3.1.2 Problem 1: Test Graph
以下各部分,请按照MIT页面上相应部分的要求,逐项列出你的设计和实现思路/过程/结果。
测试部分在完成ConcreteEdgesGraph后完成的,
GraphInstanceTest有6个函数需要完成,分别是testadd,testremove,testset,testvertices,testsources,testtarget;分别测试对应的6个函数,具体实现根据函数作用进行验证,采用assert语句进行测试,具体见代码部分。
ConcreteEdgesGraphTest有2个函数需要完成,分别是test_toString,test_Edge_toString分别用来验证ConcreteEdgesGraph类中的tostring函数和edge类走红的tostring函数
ConcreteVerticesGraphTest函数同理

3.1.3 Problem 2: Implement Graph
以下各部分,请按照MIT页面上相应部分的要求,逐项列出你的设计和实现思路/过程/结果。
3.1.3.1 Implement ConcreteEdgesGraph
完成ConcreteEdgesGraph.java部分需要参考Graph.java文件

先完成edge类,edge类有三个信息,起点,终点,权重,尽量使用private保护数据
其中checkRep函数检查起点终点是否为空,权重是否大于等于0.
构造器和get函数较简单,数据只能得到不能修改,所以只写get函数,
Tostring函数将边表达出这样的情况 Edge :begin -> end : weight

然后完成ConcreteEdgesGraph函数,
无构造器函数
checkRep函数:
1.确认边集合的起点和终点均包含在点集合里
2. 确认边集合里面没有重复的边
3.确认边集合和点集合的数据均不为空
add函数:
作用:增加新点到点集合里
检测待添加的点是否在点集合里,若不存在则添加至点集合里并返回true,否则返回false。
set函数:
作用:添加一个新边到边集合里
遍历边,如果找到这条边:weight>0,更改weight,返回旧weight;weight=0,删除这条边,返回0;weight<0,返回-1。如果没有找到这条边,添加新边,返回-1.
remove函数:
作用:删除点集合的点。
遍历点集合,如果不存在该点,则返回false,如果存在该点,则遍历边集合,将所有起点或者终点有该点的边删去,最后删除该点,返回真
Vertices函数:
作用:返回一份点集合
调用函数Collections.unmodifiableSet
Source函数:
作用:获取所有以指定顶点为终点的边的起点和权重
遍历边,建立一个Map类型的变量存储起点和权重,返回
Targets函数:
作用:获取所有以指定顶点为起点的边的终点和权重
遍历边,建立一个Map类型的变量存储起点和权重,返回
toString函数:
作用:将有向图转换成字符串
空图输出:这是一个空图,
图不为空,则将每个边的toString连接起来(调用edge类的tostring方法),调用String.concat()方法,加/n。

测试结果:

3.1.3.2 Implement ConcreteVerticesGraph
Vertex类:
vertex应该包含三个东西,分别是点的名字name,以该点为终点的所有起点和权重begins,以该点为起点的所有终点和权重ends
checkRep函数:检查begins和ends和name非空
getbegins函数:遍历以该点为终点的所有起点,将起点和对应的权重放在空图上,该方法产生递归调用
getends函数同理;
toString函数:输出格式 Vertex[name:name;begins:(begin,weight);ends:(end,weight)]

ConcreteVerticesGraph类:
checkRep函数:确定没有重复的点,确定任意一个点不为空
add函数:若vertices已包含该点则返回false,否则新建一个点,加入vertices中,返回true
其余函数基本同ConcreteEdgesGraph类中的对应函数。

测试结果:

3.1.4 Problem 3: Implement generic Graph
3.1.4.1 Make the implementations generic
将ConcreteEdgesGraph、ConcreteVerticesGraph、Edge、Vertex类等中的所有String换成L,根据eclipse的错误提示所显示的范围一个个地修改,如

Test类也需要修改,即加上,如

3.1.4.2 Implement Graph.empty()
修改Graph.empty()如下:

3.1.5 Problem 4: Poetic walks
3.1.5.1 Test GraphPoet
使用main函数里的模板进行测试,同时txt文件也是原文件

3.1.5.2 Implement GraphPoet
额外设置一个words用于存储单词
private final List words = new ArrayList(); //文本的单词

GraphPoet函数:读文件,并把文件中的单词存在words中。使用BufferedReader读取文本文件中的数据,永类Scanner将输入的文本分解成多个部分。
调用graph的set方法,将将words转化为图
checkRep函数:检查graph和words是否为空
poem函数:读取输入的内容,用split("\s")分割,按顺序与模板中的词进行匹配:若前后两个输入的词都在模板中,且夹着某个词,就将所夹的词填入内容中;若这样的词有多个,则选择weight最大的填入
toString函数:
直接return graph.toString();

测试结果:

3.1.5.3 Graph poetry slam
执行main函数结果如下:

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

3.2 Re-implement the Social Network in Lab1
在这里简要概述你对该任务的理解。
基于在3.1节Poetic Walks中定义的Graph及其两种实现,重新实现Lab1中3.3节的FriendshipGraph类。新FriendshipGraph类要利用3.1节已经实现的ConcreteEdgesGraph或ConcreteVerticesGraph,L替换为Person。根据Lab1的要求,FriendshipGraph中应提供addVertex()、addEdge()和getDistance()三个方法:针对addVertex()和addEdge()
3.2.1 FriendshipGraph类
给出你的设计和实现思路/过程/结果。
继承ConcreteEdgesGraph,
private final ConcreteEdgesGraph graph =new ConcreteEdgesGraph();
addVertex函数:在有向图中增加顶点。调用add函数。
addEdge函数:在有向图中增加边。调用set函数。
getDistance函数,修改lab1中的getDistance函数,修改的地方如下

3.2.2 Person类
给出你的设计和实现思路/过程/结果。
根据FriendshipGraph类所需要的对lab1person类进行删减
3.2.3 客户端main()
给出你的设计和实现思路/过程/结果。
使用lab1的main,代码不改变

3.2.4 测试用例
给出你的设计和实现思路/过程/结果。

3.2.5 提交至Git仓库
如何通过Git提交当前版本到GitHub上你的Lab3仓库。
在这里给出你的项目的目录结构树状示意图。

3.3 Playing Chess
3.3.1 ADT设计/实现方案
设计了哪些ADT(接口、类),各自的rep和实现,各自的mutability/ immutability说明、AF、RI、safety from rep exposure。
必要时请使用UML class diagram(请自学)描述你设计的各ADT间的关系。
Piece类:
Field:
private String Name; //棋子名称
private int State; //0未放置,1已放置。-1被remove
private int X; //横坐标
private int Y; //纵坐标
构造器:public Piece(String name,int state, int x ,int y)
方法:field的set和get函数,以及remove函数:设置x,y,state均为-1

Position类:
Field:
private int x; //横坐标
private int y; //纵坐标
构造器:
public Position(int x, int y)
方法:filed的get函数,以及equal函数:判断两个position是否相等,相等返回真,否则返回假

Player类:
Field:
private String Name; //棋手名
private Set remaining = new HashSet(); //玩家剩余棋子
private String history = new String(); //操作历史
构造器:public Player(String p)
方法;field的get函数,name的set函数,
getPiece函数:返回一个未放置的棋子
addPieces函数:增加棋子
addHistory函数:添加玩家历史
judgeOwnPiece函数:判断remaining中是否有该棋子
countPieceInBoard函数:计算player在棋盘上的棋子总数

Board类:
Field:
private int Size; //棋盘大小
private Piece[][] Position; //棋子在棋盘的位置
方法:field的set和get方法
Check函数:检查输入x,y是否超出范围
getBoardPiece函数:获得指定坐标的棋子
setBoardPosition函数:棋子放置在指定的位置
setBoardPositionState函数:改变指定位置棋子的pieceState

Action类:
Field:
private Board chessBoard = new Board();
方法: chessBoard的set和get函数
putPiece函数:将棋子放置在指定的位置
movePiece函数:将棋子移动到指定的位置
removePiece函数:移出棋子
eatPiece函数:吃棋子

Game类:
Field:
private String gameName; //游戏名
private Board gameBoard = new Board(); //棋盘
private Action gameAction = new Action(); //动作
private Player player1; //棋手1
private Player player2; //棋手2
方法:
Field对应的get函数
player1、player2、gameName的set函数
public void putPiece(Player player, Piece piece, Position position) {
gameAction.putPiece(player, piece, position);
}
public void movePiece(Player player, Position oldPosition, Position newPosition) {
gameAction.movePiece(player, oldPosition, newPosition);
}
public void removePiece(Player player, Position position) {
gameAction.removePiece(player, position);
}
public void eatPiece(Player player, Position position1, Position position2) {
gameAction.eatPiece(player, position1, position2);
}
public Piece getOccupationOfPosition(Position position) {//指定的position处获得一个棋子
return gameBoard.getBoardPiece(position.getx(),position.gety());
}
public void iniGamechess(String paName,String pbName) {//设置国际象棋chess棋盘
public void initGameGo(String name1, String name2) {//设置围棋go棋盘
public void printBoard() {//打印棋盘

3.3.2 主程序MyChessAndGoGame设计/实现方案
辅之以执行过程的截图,介绍主程序的设计和实现方案,特别是如何将用户在命令行输入的指令映射到各ADT的具体方法的执行。

由于不知名的bug导致函数运行不成功,修修改改10多个小时也没有找到真实的问题,只能遗憾终止在这

3.3.3 ADT和主程序的测试方案
介绍针对各ADT的各方法的测试方案和testing strategy。
介绍你如何对该应用进行测试用例的设计,以及具体的测试过程。
test文件基本上等于MyChessAndGoGame类
由于MyChessAndGoGame撰写的失败,测试结果也当然没有成功
测试结果:

5 实验过程中遇到的困难与解决途径
遇到的难点 解决途径
1.一开始就写test测试,完全没有头绪

调整思路,先完成P1的代码部分,再完成test的代码

2.P1的set函数无法实现对应的功能

询问同学,多次修改后仍然报错,再网上寻找思路,重新编写set代码,调整之前的代码顺序并且修改部分调用错误,实现功能

3.处理异常时让异常嵌套,结果代码量巨大,容易出错,运行慢

遇到异常就返回,检测异常,返回之后再次调用这个函数!让主函数负责对这个函数的重复调用。

4.在P1的vertex部分,vertices.contains(vertex)函数由于此时vertex是字符串,而vertices是list数组,函数需要的参数类型是Vertex,String不满足条件,故检测点集合是否包含某个点变得困难

使用遍历点集合的方法,如下

for(Vertex v1 : vertices) {
if(v1.getname().equals(vertex))
flag=1;
}
利用flag来代表点集合是否包含某个点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值