软件构造 Lab2

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

Lab 2实验报告

目录

1 实验目标概述 1
本次实验训练抽象数据类型(ADT)的设计、规约、测试,并使用面向对象编程(OOP)技术实现 ADT。 1
2 实验环境配置 1
3 实验过程 2
3.1 Poetic Walks 2
3.1.1 Get the code and prepare Git repository 2
3.1.2 Problem 1: Test Graph 2
3.1.3 Problem 2: Implement Graph 3
3.1.3.1 Implement ConcreteEdgesGraph 3
3.1.3.2 Implement ConcreteVerticesGraph 4
3.1.4 Problem 3: Implement generic Graph 5
3.1.4.1 Make the implementations generic 6
3.1.4.2 Implement Graph.empty() 6
3.1.5 Problem 4: Poetic walks 6
3.1.5.1 Test GraphPoet 6
3.1.5.2 Implement GraphPoet 6
3.1.5.3 Graph poetry slam 7
3.1.6 Before you’re done 7
3.2 Re-implement the Social Network in Lab1 8
3.2.1 FriendshipGraph类 8
3.2.2 Person类 8
3.2.3 客户端main() 9
3.2.4 测试用例 9
3.2.5 提交至Git仓库 9
3.3 Playing Chess 10
3.3.1 ADT设计/实现方案 10
3.3.2 主程序MyChessAndGoGame设计/实现方案 18
3.3.3 ADT和主程序的测试方案 19
4 实验进度记录 25
5 实验过程中遇到的困难与解决途径 26
6 实验过程中收获的经验、教训、感想 26
6.1 实验过程中收获的经验和教训 26
6.2 针对以下方面的感受 26

1 实验目标概述
本次实验训练抽象数据类型(ADT)的设计、规约、测试,并使用面向对象编程(OOP)技术实现 ADT。
本次实验训练抽象数据类型(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内部的market安装EclEmma

在这里给出你的GitHub Lab2仓库的URL地址(Lab2-学号)。
https://github.com/ComputerScienceHIT/Lab2-1153470114
3 实验过程
请仔细对照实验手册,针对三个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。
3.1 Poetic Walks
理解给出的规约描述和实验指南,完善给出的ADT框架,实现一系列图数据结构的功能,并最终通过实现的结构进行poetic应用。
3.1.1 Get the code and prepare Git repository
如何从GitHub获取该任务的代码、在本地创建git仓库、使用git管理本地开发。
通过git工具clone指令实现
3.1.2 Problem 1: Test Graph
在各个test任务中先完成instancetest类,在后面的ConcreteEgesGrapTest和ConcreteVerticesGraphTest类,这两个了类继承该类分别测试ConcreteEgesGraph和ConcreteVerticesGraph的完成情况。abstract class GraphInstanceTest类是一个抽象类无法进行测试,其正确性有继承该类的子类进行测试。
在abstract class GraphInstanceTest中对于可能在图中出现的情况进行考虑,
Add(vertex)测试:对加入vertice点进行测试,当图中没有该点时返回true,如果有该点则返回false
Remove(vertex)测试:构建一个图,对其中的节点进行移除,若图中的该点是存在的则可以移除返回true,若该点不存在则返回false,同时对于移除的点的相关联的边进行测试,是否被删除,同时当再次移除同样的点时,返回false
Vertices()测试:构建一个图调用函数的返回值是否这几个点相等
Set(vertex,vertex,point)测试:该方法设计有权重的边,测试对已经存在的点加边返回true,如果对不存在的点进行加边操作,将点加入到图中。
Sources()测试:调用测试返回相关的sources点集合
targets()测试:调用测试返回相关的targets点集合

3.1.3 Problem 2: Implement Graph
以下各部分,请按照MIT页面上相应部分的要求,逐项列出你的设计和实现思路/过程/结果。
3.1.3.1 Implement ConcreteEdgesGraph
Graph作为接口类,分别有两个具体的实现其中ConcreteEdgesGraph是一个
首先完善edge类,主要构建边的类,同时完善tostring方法。其中主要边的rep有边的权值,边的起点,边的终点,通过该类创建边。
ConcreteEdgesGraph类主要保存整个图的数据结构,主要有两部分private final Set vertices和private final List<Edge> edges两部分,该类中的方法主要对graph接口中给出的方法进行重写,主要的对上述给出的测试方法和思路,在边集中进行实现。
主要方法介绍:add:添加一个不存在的顶点
getSource:返回Source集合
getTarget:返回target集合
toString:调用每条边的toString方法,将各边一起输出
checkrep:检查不变量,其中source和target不为空,weight>0
set:输入source和target和weight确定一条有向边,创建新的边,加入新的顶点,如果weight=0删去该存在的边
remove:从点集合中删去该点,同时遍历存在的边删去起点或者终点是该点的边集
vertices:返回vertices集合

3.1.3.2 Implement ConcreteVerticesGraph
ConcreteVerticesGraph类主要通过点结构来保存整个图的数据结构,分为两部分,vertex类和ConcreteVerticesGraph类。在vertex类中主要rep有name,source and target三个rep,完成对于一个点的结构的存储,在ConcreteVerticesGraph类中对于上的点集合进行处理,构建rep:private final List<Vertex> vertices;该类中的方法主要对graph接口中给出的方法进行重写,主要的对上述给出的测试方法和思路,利用点集来进行实现。
主要方法介绍:add:添加一个不存在的顶点
getSource:返回Source集合
getTarget:返回target集合
toString:调用每条边的toString方法,将各边一起输出
checkrep:检查不变量,其中source和target不为空,weight>0
set:输入source和target和weight确定一条有向边,创建新的边,加入新的顶点,如果weight=0删去该存在的边
remove:从点集合中删去该点,同时遍历存在的边删去起点或者终点是该点的边集
vertices:返回vertices集合

3.1.4 Problem 3: Implement generic Graph
该过程主要使用泛型替代原先的String
主要的测试结果

3.1.4.1 Make the implementations generic
3.1.4.2 Implement Graph.empty()
修改Graph.empty为:
public static Graph empty() {
Graph graph = new ConcreteEdgesGraph();
return graph;
}
这里以ConcreteEdgesGraph作为Graph默认的实例类,也可以用ConcreteVerticesGraph,二者是等价的
3.1.5 Problem 4: Poetic walks
3.1.5.1 Test GraphPoet

3.1.5.2 Implement GraphPoet
将文本文件读入到结构之中按规则建立的有向图,规则为:相邻两个单词直接建立一条权值为1的有向边,有重复边时权值+1。
首先将文件以字符串形式读入,按“ ”(空格)划分为各个单词,不区分大小写,然后线性扫描,调用corpusGraph.set()建边,对input进行扩展,规则是:如果相邻两个单词a和b,在语料库中存在一个单词c使a->c和c->b都存在,则将c插入a和b之间;如果存在多个满足条件的c,取边权a->c较大的。
首先将input按“ ”(空格)划分为各个单词,不区分大小写,线性扫描,调用corpusGraph.target()和source()找出所有可能的“桥”(上面说到的c),然后找到边权最大的一个,插入。最后返回扩展好的字符串。

3.1.5.3 Graph poetry slam

3.1.6 Before you’re done
在这里给出你的项目的目录结构树状示意图。

3.2 Re-implement the Social Network in Lab1
该实验要求和lab1中相同,同时可以直接调用lab2中问题一的graph结构,通过graph结构实现该实验要求
3.2.1 FriendshipGraph类

通过ConcreteEdgesGraph实现对于FriendshipGraph的构建
主要方法:
getPersonList():通过顶点遍历寻找相同的顶点输出到outputList当中,最终返回outputList
addVertex(Person person):增加顶点调用FriendshipGraph.add(person)方法实现
addEdge(Person Person1,Person Person2):建立关系边
getDistance(Person Person1,Person Person2):返回人之间的距离,方法同lab1主要修改了调用实现对于目标的查找方法FriendshipGraph.targets(outQueuePerson).keySet()
3.2.2 Person类
较为简单只保留name和getname()方法

3.2.3 客户端main()

调用lab1中的用例进行运行输出结果
输出结果与lab1一致
3.2.4 测试用例
给出你的设计和实现思路/过程/结果。
3.2.5 提交至Git仓库
在这里给出你的项目的目录结构树状示意图。

3.3 Playing Chess
3.3.1 ADT设计/实现方案

共设计了11个类,其中Game和Action类为接口类,ChessAction和GoAction继承Action类;Chess和Go继承于Game类。下面对各类进行解释:

  1. Class position
    Rep:

构造方法:
public Position(int x,int y)
主要方法:
public void setPosition(int x,int y)
public int getPositionX()
public int getPositionY()
public boolean equals(Position pos)
构建一个位置包含xy的坐标
2. class Piece
rep:
final private String belong;
final private String type;
private Position piecePostion
构造方法:
public Piece(String belong,String type)
主要方法:

  1. class Board
    rep:
    final private int type;
    final private int size;
    private Piece[][] pieces;
    private boolean[][] placed;
    构造方法:
    public Board(int type,int size)
    主要方法:
    public Piece getPiece(int x,int y)
    public boolean setPiece(Piece p,int x,int y)
    public boolean getPlaced(int x,int y)
    public void setPlaced(int x,int y)
    public void setNotPlaced(int x,int y)
    public int getSize()
    public int getType()
  2. class Action
    这是一个接口类主要为GoAction和ChessAction具体实现
    待实现的方法:
    public Player createPlayerOne(String playerOne);
    public Player createPlayerTwo(String playerTwo);
    public Board board();
    public boolean placePiece(Player player,Piece piece,int x,int y);
    public boolean movePiece(Player player,int x,int y,int targetX,int targetY);
    public boolean removePiece(Player player,int x,int y);
    public boolean eatPiece(Player player,int x,int y,int targetX,int targetY);
  3. class ChessAction
    针对chess游戏所需要的操作进行实现
    public class ChessAction implements Action
    Rep:
    private final Board chessBoard=new Board(0,8);
    protected Player player1
    protected Player player2
    主要方法:同Action接口中的方法,主要进行具体的实现,其中象棋主要依靠
    public boolean movePiece(Player player,int x,int y,int targetX,int targetY);
    public boolean eatPiece(Player player,int x,int y,int targetX,int targetY);
    两个方法进行操作,只有在开始初始化的阶段需要调用placePiece操作进行棋子放置,在eatPiece动作中调用removePiece,对要被吃的棋子进行remove操作。
  4. class GoAction
    针对go游戏所需要的操作进行实现
    public class ChessAction implements Action
    Rep:
    private final Board chessBoard=new Board(2,18);
    protected Player player1
    protected Player player2
    主要方法:同Action接口中的方法,主要进行具体的实现,其中围棋主要依靠
    public boolean placePiece(Player player,int x,int y,int targetX,int targetY);
    public boolean removePiece(Player player,int x,int y,int targetX,int targetY);
    两个方法进行操作,不需要调用eatpiece方法和movepiece方法。
    7.class Player
    Rep:
    final private String name;
    private Set pieces=new HashSet();
    构造函数:public Player(String name)
    主要函数:
    public boolean addPiece(Piece newPiece)
    public boolean removePiece(Piece removedPiece)
    public String getName()
    8.class Game
    Game类是一个抽象类,具体的实现由GoGame和ChessGame两个类来实现。
    Rep:

主要方法:

9.class Chess
继承自Game类

构造方法:
public Chess(String game, String playerName1, String playerName2) {
super(game, playerName1, playerName2);
System.out.println(“创建chess游戏成功!玩家一”+playerName1+“玩家二:”+playerName2);
System.out.println(“玩家一:先手 玩家二:后手”);
}
主要方法:

主要设计了针对于chess游戏的内容输出output内容,针对实际的游戏操作进行输出

设计转轮系统,针对转轮输出的结果进行相应的玩家操作

同时设计选择系统,针对玩家给的选择进行相应的操作
public void chooseOfGo(String choice, Scanner in)

针对给出的规约要求实现上述的五项功能
(1)move

(2)search

(3)number of piece

(4)pass

(5)”end“

初始化操作:

9.class Go
继承自Game类

主要方法:

整体思路与Chess类相似
构造方法:

Print方法:

主要的游戏操作实现
(1)placePiece

(2)remove Piece

后续操作与Chess相同
3.3.2 主程序MyChessAndGoGame设计/实现方案

3.3.3 ADT和主程序的测试方案
通过实例演示操作进行测试:
下面首先对Chess游戏进行模拟测试:
开始游戏过程输出模拟测试:

移动棋子模拟测试:

查询棋子的模拟:

查询双方棋子个数的模拟

Pass跳过的模拟测试

End game的测试

相应的结果输出!

Go game的模拟测试:

落子方法测试:

相应结果:

吃子测试:

Search棋子测试:

棋子数量查询测试:

结束游戏测试:

通过junit进行测试:
主要测试了GoAction和ChessAction中的主要方法

主要针对上述方法中出现的各种异常情况进行测试:如果输出的点越界,输出的点不存在,移动的棋子不存在,移动的棋子不是操作者的棋子,移动情况下目标位置有棋子,吃子情况下目标位置没有棋子,等情况进行测试。
4 实验进度记录
请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。
日期 时间段 计划任务 实际完成情况
4.1 整天 操作问题一 未完成
4.2 整天 操作问题一 未完成
4.3 整天 操作问题一 未完成
4.5 整天 操作问题一 完成
4.6 整天 操作问题二 完成
4.7 整天 操作问题三 未完成
4.8 整天 操作问题三 未完成
4.9 整天 操作问题三 未完成
4.10 整天 操作问题三 完成
4.11 整天 实验报告 完成
5 实验过程中遇到的困难与解决途径
遇到的难点 解决途径

菜。

课堂学习

菜。

参考案例

菜。
课下阅读学习
6 实验过程中收获的经验、教训、感想
6.1 实验过程中收获的经验和教训
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,这些工作的意义是什么?你是否愿意在以后编程中坚持这么做?
没有。。。。感觉相对较麻烦,后期忘记处理了。但应该进行checkrep应当进行逐渐学习
(7) 关于本实验的工作量、难度、deadline。
适量,收益颇丰
(8) 《软件构造》课程进展到目前,你对该课程有何体会和建议?
非常感谢

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值