软件构造实验二

 

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

 

 

 

 

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 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。

主要有下面几个方面:

  1.  针对给定的 应用问题,从描述中识别所需 ADT
  2.  设计 ADT 的规约并评估规约的质量
  3.  根据 ADT 的规划设计测试用例,并写出 testing strategy
  4.  实现 ADT 的泛型化
  5.  根据规约设计 ADT 的多种不同的实现;针对每种实现,设计 representition、
  6. rep invariant 和 abstraction function。
  7.  使用 OOP 实现 ADT 并判定表示不变性是否违反已经是否有 rep exposure
  1. 实验环境配置

在实验一中已经配置好了

 

在这里给出你的GitHub Lab2仓库的URL地址(Lab2-学号)。

https://github.com/ComputerScienceHIT/Lab2-1180300604.git

  1. 实验过程

请仔细对照实验手册,针对三个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但千万不要把你的源代码全部粘贴过来!)。

    1. Poetic Walks

这个实验的主要目的是测试 ADT 的规约设计和 ADT 的多种不同的实现,

测试优先编程。

      1. Get the code and prepare Git repository

如何从GitHub获取该任务的代码、在本地创建git仓库、使用git管理本地开发。

使用git clone命令 到本地 移动到java项目中

      1. Problem 1: Test Graph <String>

以下各部分,请按照MIT页面上相应部分的要求,逐项列出你的设计和实现思路/过程/结果。

Graph.empty()是返回一个空的 Graph<L>实现,测试在不同的 L 的情况下,只要 L 为 immutable 类型的数据类型就可以使用。使用Integer。

 

我使用边构造法来返回图

 

      1. Problem 2: Implement Graph <String>

将 Graph<L>分别基于边为主和点为主来实现图的存储和操作。

Abstraction function

Representation invariant

checkRep

toString

都需要重写或者完善。

        1. Implement ConcreteEdgesGraph

首先根据接口重写几个函数

    public int set(L source, L target, int weight) {

        if (weight < 0) {

               throw new RuntimeException();

        }

           int r = 0;

        Iterator<Edge<L>> iterator = edges.iterator();

        while (iterator.hasNext()) {

            Edge<L> edge = iterator.next();

            if (edge.get_source().equals(source) && edge.get_target().equals(target)) {

                r = edge.get_weight();

                iterator.remove();

                break;

            }

        }

        if (weight > 0) {

            edges.add(new Edge<L>(source, target, weight));

            vertices.add(source);

            vertices.add(target);

        }

        checkRep();

        return r;

    }

Set函数与remove函数是比较麻烦的,在写的过程中发现在操作中对list做更改会报错

所以改成对容器做操作

   // Abstraction function:

   // String represent vertex, class edge represent edges

   // Representation invariant:

   // in the set of vertex the vertex can not be null

   // the edge can not be null

   // Safety from rep exposure:

   // vertices and edges are private

 

   public void checkRep() {

      for (L vertex : vertices) {

         assert (vertex != null);

      }

      for (Edge<L> edge : edges) {

         assert (edge.get_weight() > 0);

      }

   }

checkRep的检查贯穿几乎每个函数主要保证权值非负,节点非空。

 

    private  L source;

    private  L target;

    private int weight=0;

    // Abstraction function:

    /*

     * source is the start vertex of the edge, target is the end vertex of the edge

    // Representation invariant:

    /*

     * the weight of the edge must be positive source and the target must not be the

     * same one

     */

对于edge这个类的设计是用含有 三个属性 而外部是无法直接操作的

 

 

测试就是针对设计的模块,开始对异常检测不太熟练,后来发现,如果checkrep里面assert语句,可以用try catch语句检测加上fail语句检测AssertionError。同时还有一些

RuntimeException。

 

 

 

 

 

        1. Implement ConcreteVerticesGraph

这种方法和用edge的list表示一个图的区别主要是其属性包含一个节点,根据图论的知识,每个点都有出度和入度,有出去的边,有进来的边。所以很多操作都要改变其他顶点和该顶点的联系,要从list里面找到匹配的节点,这相比上一种实现有一些麻烦。

       // Abstraction function:

       /*

        * list of vertex represent the nodes in the graph class vertex can be a node

        * which contains out coming edge and out come edge

        */

 

       // Representation invariant:

       /*

        * the weight of the edge should not <= 0 the source and the target should not

        * be same the number of in coming edge must be same as the out coming edge

        */

       // Safety from rep exposure:

       /*

        * vertices is private vertex can not be changed by outside

        */

 

该类里需要注意的同样是要权值为正,节点非空,source节点和target节点要不一样,和上一种实现基本一致,但相对数据结构的checkrep有一些区别。

 

 

 

private L node;

       private Map<L, Integer> inedge = new HashMap<L, Integer>();

       private Map<L, Integer> outedge = new HashMap<L, Integer>();

       // Abstraction function:

       // TODO

       /*

        * the node is the vertex inedge is in coming edge outedge is out coming edge if

        * you find that a node's inedge is same as a node's out coming edge. You can

        * say that one is the source and the other is the target.

        */

       // Representation invariant:

       // TODO

       /*

        * the weight of the edge must >= 0 the number of the in coming edges must be

        * same the out edges. the node can not be node

        *

        */

       // Safety from rep exposure:

       // TODO

       // the inedges and outedges cannot be get outside

Node类里面涉及对于出边入边的一些操作,设置出边,设置入边,消去出边,消去入边

 

 

 

有几个模块的测试打包在了test测试函数里

 

 

 

      1. Problem 3: Implement generic Graph<L>

将已有的两个 Graph<String>的实现改为基于 Graph<L>的实现

 

        1. Make the implementations generic

注意将所有的实现全部改为泛型实现即可,然后在更改结束后,重新测试

ConcreteVerticesGraphTest 和 ConcreteEdgesGraphTest 两个测试,可以

测试通过。

 

        1. Implement Graph.empty()

1、graph.empty 返回一个 Graph 接口的具体实现即可,如

    public static <L> Graph<L> empty() {

//        throw new RuntimeException("not implemented");

        return new ConcreteEdgesGraph<>()}

2、测试 GraphStaticTest

 使用不同的 L 泛型进行测试,基本数据类型均是 Immutable 类的,

。此处采用 Integer进行了测试,具体的测试结果如下

 

 

 

 

 

 

 

 

 

 

 

      1. Problem 4: Poetic walks

“诗意之旅”这个任务主要利用已有的图的接口,根据一段诗生成其对应的图,

然后根据这个生成的图再生成更多的诗

 

        1. Test GraphPoet

 

主要测试了在空文件 单行输入 多行输入的情况下是否能够通过测试

        1. Implement GraphPoet

 

public GraphPoet(File corpus)

根据输入改变对应map的权值

public String poem(String input)

根据输入,对应的map 添加桥接词

 

 

        1. Graph poetry slam

使用了自带的txt文件进行测试

 

 

 

      1. Before you’re done

 

 

 

 

请按照http://web.mit.edu/6.031/www/sp17/psets/ps2/#before_youre_done的说明,检查你的程序。

如何通过Git提交当前版本到GitHub上你的Lab2仓库。

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

    1. Re-implement the Social Network in Lab1

重新实现 Lab1 中的 Social Network,利用在 P1 中已经写

好的 Graph<L>接口来实现

在这里简要概述你对该任务的理解。

      1. FriendshipGraph

使用 Graph<L>里面提供的函数 add,即可实现增加顶点的功能。只需

要在 addVertex 中在增加对于 distance 和 visited

 

实现 addEdge 函数

利用 Graph<L>里面提供的函数 set,可实现增加顶点

addEdge 中判断一下是否是源点和目的点是否相同即可

利用set(person1, person2,1)增加边。

实现 getDistance 函数

 

 

 

 

 

 

这里使用了队列,因为用搜索算法的时候,需要队列这种先进先出的特性

 

给出你的设计和实现思路/过程/结果。

      1. Person

 

由一个构造方法和一个getname组成

给出你的设计和实现思路/过程/结果。

      1. 客户端main()

 

重新利用 Lab1 中已有的 main 客户端即可

给出你的设计和实现思路/过程/结果。

      1. 测试用例

           FriendshipGraph graph = new FriendshipGraph();

              Person rachel = new Person("Rachel");

              Person ross = new Person("Ross");

              Person ben = new Person("Ben");

              Person kramer = new Person("Kramer");

              Person KKK = new Person("KKK");

              Person AAA = new Person("AAA");

             

             

              graph.addVertex(rachel);

              graph.addVertex(ross);

              graph.addVertex(ben);

              graph.addVertex(kramer);

              graph.addVertex(KKK);

              graph.addVertex(AAA);

             

             

              graph.addEdge(ross, ben);

              graph.addEdge(ben, ross);

              graph.addEdge(ross,KKK );

              graph.addEdge(KKK, ross);

              graph.addEdge(KKK, AAA);

              graph.addEdge(AAA, KKK);

              graph.addEdge(rachel, ross);

              graph.addEdge(ross, rachel);

 

                           

              assertEquals(-1,graph.getDistance(rachel,kramer));

              assertEquals(3,graph.getDistance(rachel,AAA));

              assertEquals(2,graph.getDistance(ben,KKK));

              assertEquals(1,graph.getDistance(rachel,ross));

              assertEquals(2,graph.getDistance(rachel,ben));

              assertEquals(0,graph.getDistance(rachel,rachel));

 

 

看是否能够满足最基本的功能,在改写过后,进行测试,全部通过,其实还可以对空图测试、仅有顶点的图测试、无环图测试和有环图测试,时间有限还没来得及写测试。

 

 

给出你的设计和实现思路/过程/结果。

      1. 提交至Git仓库

使用git命令即可

Add commit push等等

 

 

如何通过Git提交当前版本到GitHub上你的Lab3仓库。

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

    1. Playing Chess

 

      1. ADT设计/实现方案

 

设计了哪些ADT(接口、类),各自的rep和实现,各自的mutability/ immutability说明、AF、RI、safety from rep exposure。

 

 

 

 

 

 

整体来说,有一个主类,里面有一个主函数,用来控制控制台,控制台流程和要求里的基本一致,用户 选择一个游戏,输入玩家名字,然后给出一系列指令范例

程序会创建两个player类每个里面包含一些玩家特征,比较重要的是一个action类的list用来存储每个玩家的操作。

 

 

 

用户根据样例键入指令,主程序用split函数分解指令 swich语句根据不同操作指令做出动作,调用board类中的方法对棋盘上的棋子做出操作,board类会调用position中的方法。

在每一次的操作中,创建一个action类,将该类添到对应player的action类list里面。

 

 

 

Position

/*

 * AF

 * position represent the state of that point

 * color is black or white

 * type is "chess" or "go"

 *

 * RI

 * x,y is in a range

 * color is only two kinds

 * type is only chess or go

 * */

public class Position {

       int x;

       int y;

       boolean visited;

       String type;

       boolean color;

       Position(int x,int y,boolean color,String type)

       {

              this.x=x;

              this.y=y;

              this.color=color;

              this.type=type;

       }

首先是position 类 他表达了棋盘上的某一个坐标的状态,是否有子,什么颜色等等

 

Player

 

包含上述属性

安全性:全部通过方法访问属性

 

Action

 

 

里面存储了action的许多方法

用来改变和访问类里的属性

 

比较重要的是get_position方法可以根据传入游戏类型输出不同格式的操作

在主函数中被迭代调用

 

 

 

 

 

 

 

 

 

Position

 

 

 

 

 

 

 

 

 

 

 

 

 

Board

 

 

      1. 主程序MyChessAndGoGame设计/实现方案

Go

 

 

Chess

 

 

 

  1. 用户输入 棋类名字 chess or go
  2. 根据不同棋类调用board类里的初始化函数初始化棋盘
  3. 给用户打印指令样例
  4. 用户输入指令
  5. 将字符串拆分存入数组,访问数组0位关键指令,同时使用switch 映射到board中的方法,对棋盘操作,同时记录下当前player的action,存入该player的action数组
  6. 输入end结束
  7. 询问是否需要打印步骤图
  8. 若要打印则分别先后打印player1 和player2的步骤

 

 

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

      1. ADT和主程序的测试方案

 

 

 

 

 

 

分别单独测试board里的方法 move eat put remove

测试成功

 

 

 

加入部分主程序 在主程序运行过程中加以测试

 

介绍针对各ADT的各方法的测试方案和testing strategy。

介绍你如何对该应用进行测试用例的设计,以及具体的测试过程。

  1. 实验进度记录

请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。

每次结束编程时,请向该表格中增加一行。不要事后胡乱填写。

不要嫌烦,该表格可帮助你汇总你在每个任务上付出的时间和精力,发现自己不擅长的任务,后续有意识的弥补。

日期

时间段

计划任务

实际完成情况

3.28

20:00-1:00

完成P1

完全没有看懂……英语太差,到差不多12点才大致能够理解让做什么东西

4.1

20:00-24:00

完成P1

完成了P1的所有测试

4.2

20:00-1:00

完成P1

完成了以边为基础的构造方法

4.3

20:00-24:00

完成P1

完成了以点为基础的构造方法

4.4

20:00-24:00

完成P2

完成

4.5

20:00-1:00

完成P3

设计ADT 编写测试

4.9

20:00-1:00

完成P3

实现部分类

4.12

20:00-1:00

完成P3

实现部分类

  1. 实验过程中遇到的困难与解决途径

遇到的难点

解决途径

不太能理解网站上的描述,

英语不太好,难以理解任务要求,不具备测试优先的思想,或者熟练的ADT设计习惯。

不断重复的阅读,理解要求,上网查阅资料,看学长写的报告

容器 队列 list用的不太好

 

 

看java书

以vertex为基础建立图的时候对于图的知识忘的很多了

 

 

翻看离散数学引论 发现出度入度

棋类游戏没啥思绪

 

多次阅读要求,拿草纸设计

 

 

 

 

  1. 实验过程中收获的经验、教训、感想
    1. 实验过程中收获的经验和教训

实验设计的本身是很好的,但是自己java 和OOP技术比较欠缺,自己还需要去看书,学习java编程技术

    1. 针对以下方面的感受
  1. 面向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. 《软件构造》课程进展到目前,你对该课程有何体会和建议?

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值