软件构造实验二报告

 

目录

 

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 主程序ChessGame设计/实现方案···· 3

3.3.3 ADT和主程序的测试方案···· 3

3.4 Multi-Startup Set (MIT) 4

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 并据此设计测试用例。

 

  1. 实验环境配置

在本地机器安装相应的开发环境JDK、Eclipse、Git

并在自己的Eclipse IDE中安装配置Junit

了解如何使用JUnit为Java程序编写测试代码并执行测试

没有遇到问题,一切都很顺利。

地址:https://github.com/ComputerScienceHIT/Lab2-1170300724

  1. 实验过程

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

    1. Poetic Walks

分别新建两个类ConcreteEdgesGraph,ConcreteVerticesGraph 实现Graph接口。

Graph接口要求实现add(添加新节点),set(添加新边),remove(移除节点),vertices(获得所有的节点集合),sources(target)获得以target为目标节点的边的起始节点,targes(source)获得以source为起始节点的边的目标节点。

对于problem4,我们则需要根据文件中的输入,构造poet,再由input和图中的映射关系,得出最后的poem。

      1. Get the code and prepare Git repository

Git init

Git remote add origin [email protected]:ComputerScienceHIT/Lab2-1170300724.git

Git pull origin master

Git add .

Git commit -m “init”

Git push origin master

代码是从网上下载的

      1. Problem 1: Test Graph

将Graph里原empty()方法修改为:

Return new concreteEdgesGraph();

再运行GraphStaticTest就可以得到结果了。

      1. Problem 2: Implement Graph

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

        1. Implement ConcreteEdgesGraph

public boolean add(L vertex)

直接调用add函数,判断如果原本就有就返回false

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

如果weight>0 没找到指定的边,就把这个边加进去,如果找到了这个边,就更新这个边,如果weight=0 找到了这个边,就将这个边删除。

public boolean remove(L vertex)

如果没找到要删除的边,就返回false,否则就遍历,找到某个edge的source或是target与vertex相等,删除边,再删除vertex

public Set vertices()

返回vertex的set

public Map sources(L target)

建立一个map,遍历edges,如果某个edge的target和传入target相等,则将该边的source和weight存入map中。

public Map targets(L source)

建立一个map,遍历edges,如果某个edge的source和传入source相等,则将该边的target和weight存入map中。

public String toString()

主要就是增加可读性toString都是现成的

 

class Edge

public Edge(L start,L end,int value)

这个类要有三个重要的东西在里面,start,end,和value

所以可以知道,里面的方法就是调用这三个量。

private void checkRep()

主要是保证value大于0

public String toString()

增加可读性,表示里面的量都是啥。

        1. Implement ConcreteVerticesGraph

public boolean add(L vertex)

若vertices()中已包含vertex,返回false,否则新建一个顶点将其加入vertices。

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

如果存在vertices()中找到source,找到源点,否则以source为string创建一个新的源点,并将它添加进vertices。对于target操作同理。

得到源点和目标点后,分别对目标点调用addSource,源点调用addTarget即可。

public boolean remove(L vertex)

先判断存不存在这个点,如果不存在就返回false,如果存在遍历所有的点,删掉这个点,而且还要删掉所有有关系的东西

public Set vertices()

遍历vertices,找到每个点对应的name,添加进set。

public Map sources(L target)

如果找到了目标的target点,就返回对应的source,如果没找到,返回一个空的map

public Map targets(L source)

如果找到了目标的target点,就返回对应的target,如果没找到,返回一个空的map

public String toString()

增加可读性。

 

class Vertex

private L name;

private Map target;

private Map source;

里面需要有重要的三个东西,name,target,source

    public L name() {

       L nameString=this.name;

       return nameString;

    }

    public Map asktarget(){

       return this.target;

    }

    public Map asksource(){

       return this.source;

    }

    public void setName(L name) {

       this.name=name;

    }

    public void setTarget(Map targetMap) {

       this.target=targetMap;

    }

    public void setSource(Map sourceMap) {

       this.source=sourceMap;

    }

    public void addtarget(L target,int weight) {

       this.target.put(target, weight);

    }

    public void addsource(L source,int weight) {

       this.source.put(source, weight);

    }

    public void removetarget(L target) {

       this.target.remove(target);

    }

    public void removesource(L source) {

       this.source.remove(source);

}

需要实现的功能是,访问name,target,source,设置name,target,source,删除name,target,source

public String toString()

增加可读性。

public void checkRep()

检测不变性。

 

      1. Problem 3: Implement generic Graph
        1. Make the implementations generic

主要是把string都改成L,class <>L的实现分别写在两个java分析里面了

以前,可能已声明类型为Edge或变量List要改为Edge和List>。

同样,可能已经调用了类似new ConcreteEdgesGraph()或构造函数new Edge()要改为new ConcreteEdgesGraph()和new Edge()。

        1. Implement Graph.empty()

    public static Graph empty() {

        return new ConcreteEdgesGraph();

}

需要将empty改成这样

      1. Problem 4: Poetic walks
        1. Test GraphPoet

test测试如下

public class GraphPoetTest {

   

    @Test(expected=AssertionError.class)

    public void testAssertionsEnabled() {

        assert false; // make sure assertions are enabled with VM argument: -ea

    }

    @Test

    public void TestGraphPoet() throws IOException {

       final GraphPoet graph = new GraphPoet(new File("src/P1/poet/mugar-omni-theater.txt"));     

        final String input = "Test the Theater system.";

        System.out.println(graph.temp);

        System.out.println(input + "\n>>>\n" + graph.poem(input));

        assertEquals("test of the theater sound system.", graph.poem(input));

    }

    @Test

    public void Testpoem() throws IOException {

       final GraphPoet graph = new GraphPoet(new File("src/P1/poet/mugar-omni-theater.txt"));     

        final String input = "Test the Theater system.";

        System.out.println(input + "\n>>>\n" + graph.poem(input));

        assertEquals("test of the theater sound system.", graph.poem(input));

    }

}

给定一个input。从文件中读取poet,调用Graph.poem()后看是否与预期相同

        1. Implement GraphPoet

public GraphPoet(File corpus) throws IOException

从语料库的图形中创建一个新的poet。

先读文件,并把文件中的单词存在words中。使用BufferedReader读取文本文件中的数据,类Scanner用于将输入的文本分解成多个部分。

然后调用Graph类中的方法,将单词转化为图,添加顶点,set边,其中权值全部设置为1.

public String poem(String input)

遍历input中所有单词,调用Graph.targets()和Graph.sources()方法。如果该单词的targets和后面一个单词的sources有交集,则添加一条bridge,并且在两个单词的bridge中随机选择一个插入到字符串中。

public String toString() {

       return  temp.toString();

        1. Graph poetry slam

Main函数实现如下

public class Main {

   

    /**

     * Generate example poetry.

     *

     * @param args unused

     * @throws IOException if a poet corpus file cannot be found or read

     */

    public static void main(String[] args) throws IOException {

           final GraphPoet graph = new GraphPoet(new File("src/P1/poet/mugar-omni-theater.txt"));        

        final String input = "Test the Theater system.";

        System.out.println(graph.temp);

        System.out.println(input + "\n>>>\n" + graph.poem(input));

    }

   

      1. Before you’re done

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

Lab2_1170300724

 

src

 

P1

 

graph

 

….java

 

poet

 

… .java

 

… .txt

 

test

 

P1

 

graph

 

…Test.java

 

poet

 

… Test.java

 

… .txt

    1. Re-implement the Social Network in Lab1

继承P1中ConcreteEdgesGraph或者ConcreteVerticesGraph类 实现FriendshipGraph(这个是lab1里的内容)

      1. FriendshipGraph类

public class FriendshipGraph extends ConcreteVerticesGraph

利用的是p1里的ConcreteVerticesGraph

public int addEdge(Person p1,Person p2)

调用set(p1,p2,1)

public boolean addVertex

调用.add添加人

public int getDistance(Person p1, Person p2)

利用广度优先搜索,需要用到队列。

广度优先遍历就是将p1入队,设置访问过出队,然后将它的相邻点入队,设置访问过,直到找到p2,给出距离,如果全都访问过也没找到p2,则返回-1

调用.target获得相邻点

      1. Person类

       private String name;

       public Person(String name) {

                     this.name=name.toLowerCase();

       }

       public String Name() {

              return this.name;

       }

       public void setName(String newname) {

              this.name=newname;

       }

存储名字,访问名字,设置名字

    public boolean equals(Object obj) {

        if (obj instanceof Person) {

            Person person= (Person) obj;

            return name.equalsIgnoreCase(person.Name().trim());

        }

        return false;

    }

判断是否有重复的名字

      1. 客户端main()

测试代码和lab1的类似

      1. 测试用例

需要测试addVertex,addEdge,其中包括重名情况,

测试getDistance其中包括没有路径的情况

      1. 提交至Git仓库

Lab2_1170300724

 

src

 

P2

 

FriendshipGraph.java

 

Person.java ...

 

test

 

P2

 

FriendshipGraphTest.java

    1. Playing Chess
      1. ADT设计/实现方案

Board

public class Board

public Board(Game game) 根据输入的游戏不同创建两种不同的棋盘。

国际象棋初始是有棋子的,所以要対初始棋子进行初始化,对应位置给对应的名字,围棋就简单的给出一个空白棋盘,记得空白也是要初始化的。

public int getsize()

返回棋盘的大小

public Position findPosition(int x,int y)

返回这个位置的Position类

 

Game

public class Game

    public Game(String name)

    {

       this.name=name;

    }

    public String getname()

    {

       return name;

    }

就是一个存游戏名字的类

 

Piece

public class Piece

    public Piece(String name,boolean color)

    {

       this.name=name;

       this.color=color;

    }

   

    public boolean getcolor()

    {

       boolean gtemp=this.color;

       return gtemp;

    }

    public String getname()

    {

       return this.name;

    }

就是个存棋子的类,可以分角色记录。

 

Player

public class Player

    public Player(String name,boolean color)

    {

       this.color=color;

       this.name=name;

    }

   

    public boolean getcolor()

    {

       boolean gtemp=color;

       return gtemp;

    }

   

    public String getname()

    {

       return name;

    }

就是个存玩家名字和颜色(分边)的类

 

Position

public class Position

这是一个用于存对应位置对应棋子的类,根据主要代码写的,有两种存储方式,一种是int int 输入,一种是int int Piece 输入,只输出了Piece,因为位置的两个int并没有用到。

public boolean set_piece(Piece piece)

在对应位置设置棋子

 

Action

public boolean put_in(int x,int y,boolean color)

针对围棋的一种下棋动作

public boolean change(int x1,int y1,int x2,int y2,boolean color)

针对国际象棋的位移,就是把一个棋子下到另一个位置,因为国际象棋你也不能新建一个棋子出来啊

public boolean remove(int x,int y,boolean color)

吃子,判定,你不能吃自己的子,不能吃空白的子。(实际上只是移除,把原本位置变成空白写在了主函数里面)

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

Field:

class Chess

{

    Player historyPlayer;

    Piece historyPiece;

    int command;

    int x1;

    int y1;

    int x2;

    int y2;

    public Chess(Player player,int command)

    {

        this.historyPlayer=player;

        this.command=command;

        x1=-1;

    }

    public Chess(Player player,Piece piece,int x1,int x2,int y1,int y2,int command)

    {

        this.historyPlayer=player;

        this.historyPiece=piece;

        this.x1=x1;

        this.x2=x2;

        this.y1=y1;

        this.y2=y2;

        this.command=command;

    }

    @Override public String toString()

    {

        String temp=historyPlayer.getname()+" : "+command;

        if(x1>=0)

            temp=temp+" from "+x1+" "+y1+" to "+x2+" "+y2;

        return temp;

    }

}

class Go

{

    Player historyPlayer;

    int x;

    int y;

    int command;

    public Go(Player player,int command)

    {

        this.historyPlayer=player;

        this.command=command;

        x=-1;

        y=-1;

    }

    public Go(Player player,int x,int y,int command)

    {

        this.historyPlayer=player;

        this.x=x;

        this.y=y;

        this.command=command;

    }

    @Override public String toString()

    {

        String temp=historyPlayer.getname()+" : "+command;

        if(x>0)

            temp=temp+" direction "+x+" "+y;

        return temp;

    }

}

得先创建两个游戏类的游戏类,方便实现以后的功能。

public boolean chushi()

    {

        Scanner Scanner=new Scanner(System.in);

        String temp;

        System.out.println("chess or go to play");

        temp=Scanner.nextLine();

        if(temp.toLowerCase().equals("chess")==true||temp.toLowerCase().equals("go")==true)

        {

            Game=new Game(temp);

            Board=new Board(Game);

            Action=new Action(Game,Board);

        }

        else

        {

            System.out.println("Err");

            return false;

        }

        System.out.println("Please input Player1's name");

        temp=Scanner.nextLine();

        play1=new Player(temp, false);

        System.out.println("Please input Player2's name");

        temp=Scanner.nextLine();

        play2=new Player(temp, true);

        return true;

    }

这个是初始棋盘的代码,没有单独的游戏菜单,在这步输入游戏类别和游戏玩家名。

       public boolean step(boolean forward,Player now_Player)

主要的步骤函数

首先区别围棋和国际象棋,然后给出菜单选项,再根据输入的选项实现各个功能

围棋:

1:放子   2:提子   3:跳过   4:结束 5:查子 6:算子

如果是1:调用Action.put_in 判断下棋,然后加到围棋历史里面

如果是2:调用Action.remove 吃子,加到历史里面

如果是3:啥也不调用,直接加一次历史

如果是4:将判定游戏结束的变量改成true

如果是5:调用Piece.getname和Piece.getcolor 加一次历史

如果是6:遍历棋盘,记录所有不是空白的子(分颜色)

国际象棋:

1:移动   2:吃子   3:跳过   4:结束   5:查子 6:算子"

大部分都一样

特殊的是1:调用Action.change和Board.findPosition

2:调用Action.remove Action.change Board.findPosition Position.geiPiece

5查子:现根据输入的位置,调用Board.findPosition(x, y).getpiece()先确定棋子,再根据棋子的不同使用不同的输出

    public static void main(String[] args)

    {

       MyChessAndGoGame temp=new MyChessAndGoGame();

       while(temp.chushi()==false);

       for(int i=1;temp.gameover==false;i++)

       {

           if(i%2==1)

              while(temp.step(false, temp.play1)==false);

           else

              while(temp.step(true, temp.play2)==false);

       }

       if(temp.Game.getname().equals("chess"))

       {

           for(Chess k:temp.Chess)

              System.out.println(k.toString());

       }

       else

       {

           for(Go k:temp.Go)

              System.out.println(k.toString());

       }

    }

最后main函数,实现整体的结构功能。

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

软件构造实验二报告_第1张图片

软件构造实验二报告_第2张图片

软件构造实验二报告_第3张图片

    1. Multi-Startup Set (MIT)

请自行设计目录结构。

注意:该任务为选做,不评判,不计分。

  1. 实验进度记录

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

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

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

日期

时间段

计划任务

实际完成情况

3.29

15:00-19:00

P1 的graph

完成

3.30

15:00-19:00

P1的poet

完成

4.3

16:00-18:00

P2

完成

4.5-4.7

14:00-16:00

P3的全部内容

完成

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

遇到的难点

解决途径

 

P1的实验要求理解不清楚

 

谷歌翻译,结合同学的实际情况

 

P3的结构无法理清

 

采用了网上的建议和结构

  1. 实验过程中收获的经验、教训、感想
    1. 实验过程中收获的经验和教训
    2. 针对以下方面的感受

谈到Java编程那就不得不提及其中的抽象数据类型,以及面向对象编程。本次的实验而当中便是对这方面的学习进行的巩固。

如果思维方式是:我先做什么,再做什么……这叫面向过程;

如果思维方式是:我先做一个什么东西来做这件事,再做一个什么东西来做那件事,然后它们怎么相互配合……这叫面向对象。

面向过程更像是我们一开始接触编程,只是为了实现某个功能。而现在我们应该做的是多考虑面向对象,这样才有利于程序的可扩展性。

泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用。泛型可以简化代码,保证代码质量。

这样可以加深自己对于spec的了解,不会忘记一些边界条件的限制导致低效率的debug,效率更高,更加方便,可以适应这种测试方式

复用可以减少相同代码再次编写的浪费时间,简化代码提高效率

所有的类都要自己设计肯定更复杂,但自由度更高,不会有理解上的困难

帮助我们时刻保持清醒,spec确定自己代码应该满足的条件,RI, AF题型自己ADT是如何设计的,不会产生前后矛盾的情况,rep exposure保证了自己程序的健壮性、安全性,是程序重要的性质,这些工作为我们养成了良好的编程习惯,是非常有必要的。

时间设计的很合理,充裕又不会太慢。

你可能感兴趣的:(软件构造实验二报告)