软件构造-实验二-仅供参考

 

 

 

 

 

 

 

 

 

 

姓名

 

学号

 

班号

 

电子邮件

 

手机号码

 

 


 

目录

 

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 主程序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 实验目标概述

2 本次实验训练抽象数据类型(ADT)的设计、规约、测试,并使用面向对象 编程(OOP)技术实现 ADT。具体来说:

3  ⚫ 针对给定的应用问题,从问题描述中识别所需的 ADT;

4 ⚫ 设计 ADT 规约(pre-condition、post-condition)并评估规约的质量;

5 ⚫ 根据 ADT 的规约设计测试用例;

6 ⚫ ADT 的泛型化;

7 ⚫ 根据规约设计 ADT 的多种不同的实现;针对每种实现,设计其表示 (representation)、表示不变性(rep invariant)、抽象过程(abstraction function)

8 ⚫ 使用 OOP 实现 ADT,并判定表示不变性是否违反、各实现是否存在表 示泄露(rep exposure);

9 ⚫ 测试 ADT 的实现并评估测试的覆盖度;

10 ⚫ 使用 ADT 及其实现,为应用问题开发程序; ⚫ 在测试代码中,能够写出 testing strategy 并据此设计测试用例。

11 实验环境配置

安装jdk 随意选择目录 只需把默认安装目录 \java 之前的目录修改即可

安装jre→更改→ \java 之前目录和安装 jdk 目录相同即可

安装完JDK后配置环境变量  计算机→属性→高级系统设置→高级→环境变量

系统变量→新建 JAVA_HOME 变量 。

变量值填写jdk的安装目录

系统变量→寻找 Path 变量→编辑

在变量值最后输入 %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;

系统变量→新建 CLASSPATH 变量

变量值填写   .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar(注意最前面有一点)

 

12 实验过程

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

12.1 Poetic Walks

图是一个比较基本的数据类型,本次实验通过实现图的数据结构来熟悉软件构造中ADT和OOP技术。

12.1.1 Get the code and prepare Git repository

代码在GitHub中点击按钮就可以下载到本地,也可以使用URL下载到本地,还有GitHub的客户端进行管理。客户端的功能很全面,能实现克隆代码上传等功能。

12.1.2 Problem 1: Test Graph <String>

在Lab1的时候学到了测试类,知道了测试的重要性。

12.1.3 Problem 2: Implement Graph <String>

通过课堂的学习我知道这只是一个ADT,它存在的目的就是提供接口,我们可以通过继承来进行向上转型从而对程序有更好的扩展性。

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

这个函数的作用就是生成一个空的graph,等着我们实现concreteedgesgrraphD的时候才能实现

public boolean add(L vertex);  增加节点

public int set(L source, L target, int weight);  设置一条边的权重

public boolean remove(L vertex);  移走一个节点

public Set<L> vertices();  节点的集合

public Map<L, Integer> sources(L target);  获得指向这个节点的节点和权重返回

public Map<L, Integer> targets(L source);  获得所有这个节点指向的节点和权重,然后返回。

12.1.3.1 Implement ConcreteEdgesGraph

这是具体实现

private void checkRep()  负责对保存的数据进行实时的检测,每个方法中都要包含

@Override

public boolean add(String vertex)

重写了add函数,判断这个顶点是否在集合中,如果不在,那么就加入到这个集合中,重写的目的是适应string这个类型的变量

@Override

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

这个同样是一个重写,生成一个边,然后判断边和顶点和边是否在集合中,进行设定

@Override

    public boolean remove(String vertex)

这个重写的目的在于要移除一个顶点和这个顶点所在的边

@Override

    public Set<String> vertices()

这个目的是返回顶点的集合

@Override

    public Map<String, Integer> sources(String target)

返回所有指向这个顶点的边组成的图

@Override

    public Map<String, Integer> targets(String source)

返回所有这个顶点指向的边组成的顶点

public String toString()

进行形象化的输出

class Edge  这个类是最底层的类,就是边,然后有一些对外的接口。

12.1.3.2 Implement ConcreteVerticesGraph

private void checkRep()  这个函数的用处在实验报告中要求的是随时检查变量是否不变。

@Override

public boolean add(String vertex)

重写的目的是添加顶点

@Override

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

重写的目的是重新设置顶点的权值

@Override

    public boolean remove(String vertex)

从集合中移除顶点

@Override

    public Set<String> vertices()

返回顶点的集合

@Override

    public Map<String, Integer> sources(String target)

返回所有指向这个顶点的图

@Override

    public Map<String, Integer> sources(String target)

返回所这个顶点指向的图

class Vertex  这个类就是声明了顶点的权值

 

 

 

 

发现覆盖率有的很高有的很低。

12.1.4 Problem 3: Implement generic Graph<L>

12.1.4.1 Make the implementations generic

前面我们的范式是string,有局限性,我们希望可以有拓展性。

12.1.4.2 Implement Graph.empty()

 

 

向上转型直接返回即可

12.1.5 Problem 4: Poetic walks

应用图,我们应该提供一些语句分解作为资料库,然后将两个单词之间都设为一条边和权重就是出现次数。

12.1.5.1 Test GraphPoet

我们在文件中写资料库,输入句子,要求输入的句子间的单词被添加

12.1.5.2 Implement GraphPoet

其中的方法有checkrep,poem,tostring还有一个构造器。实验的目标很简单,简单来说就是我们的资料库中两个单词之间有连接词,如果我们输入的句子这两个单词是连在一起的,那么输出这两个单词之间应该被填上连接词。

在构造器中我们就将资料库中的单词分开并且转换成小写储存 起来,在poem中拿来与输入的句子进行比较。

 

12.1.5.3 Graph poetry slam

资料库中的东西可以进行扩展。

12.1.6 Before you’re done

 

12.2 Re-implement the Social Network in Lab1

让我们通过不同的写法来实现程序的组合功能,程序的可扩展性体现了出来

12.2.1 FriendshipGraph类

运用上面P1写好的类,我将graph稍微改动写成了frendshipgraph类。

12.2.2 Person类

在程序的开始我是先写的person类,因为这个是最基础的,就是将LAB1实现的功能再写一遍。

12.2.3 客户端main()

FriendShipGraph graph = new FriendShipGraph();

            Person rachel = new Person("Rachel");

            Person ross = new Person("Ross");

            Person ben = new Person("Ben");

            Person kramer = new Person("Kramer");

            graph.addVertex(rachel);

            graph.addVertex(ross);

            graph.addVertex(ben);

            

            graph.addVertex(kramer);

            graph.addEdge(rachel, ross);

            graph.addEdge(ross, rachel);

            graph.addEdge(ross, ben);

            graph.addEdge(ben, ross);

          

            System.out.println(graph.getDistance(rachel,ross));

            //should print 1

            System.out.println(graph.getDistance(rachel,ben));

            //should print 2

            System.out.println(graph.getDistance(rachel,rachel));

            //should print 0

            System.out.println(graph.getDistance(rachel,kramer));

            //should print -1

Main函数就是上次的函数

 

 

12.2.4 测试用例

测试用例就是在上次提供的main函数上加加减减,覆盖率高一些。

12.2.5 提交至Git仓库

 

12.3 Playing Chess

12.3.1 ADT设计/实现方案

一共写了action board chessaction chesspiece game goaction gopiece mychessandgogame piece player position 这几个类,其中position类是最低层的,其次是piece有对象包括了positon ,player中实现了玩家添加和棋子之间的关系,有piece的集合,有相当一部分是接口。就是将playername gamehistory都提供一个接口。Board会根据是要国际象棋还是围棋来创建二维数组。Chessaction和goaction都是继承子action分别对象棋和围棋做出了加子,移动棋子或去掉棋子的操作

12.3.2 主程序MyChessAndGoGame设计/实现方案

 

System.out.print("input: \n1.Chess\n2.Go\n");

        Scanner input=new Scanner(System.in);

        int temp1=input.nextInt();

        Board board=new Board(temp1);//初始化棋盘,输入两个对弈者

        ChessAction myaction=new ChessAction();

        GoAction myAction2=new GoAction();

        /*System.out.println("input x");

        int x=input.nextInt();

        System.out.println("input y");

        int y=input.nextInt();

        Position pos=new Position(x, y);*/

        if(temp1==1)

        {

             String endString="start";

             while(!endString.equals("end"))

             {

                   System.out.println("是否要继续输入,结束输入end");

                   System.out.println("input :");

                   endString=input.next();

                   System.out.println("input x");

                   int x=input.nextInt();

                   System.out.println("input y");

                   int y=input.nextInt();

                   Position pos=new Position(x, y);

                   System.out.println(" --------------------------");

                   System.out.println("你想进行什么操作?");

                   System.out.println("3 .移动棋盘某个坐标的子");

                   System.out.println("4 .吃掉棋盘的某个坐标的子");

                   System.out.println("input");

                   int choose=input.nextInt();

                  

                  

                        if(choose==3)

                         {

                              System.out.println("input target x");

                              int a=input.nextInt();

                              System.out.println("input target y");

                              int b=input.nextInt();

                              Position targetPosition=new Position(a, b);

                              myaction.chessmove(pos, targetPosition);

                        }

                        if(choose==4)

                        {

                              myaction.chesseat(pos);

                        }

                       

                  

                   /*else

                   {

                      System.out.println("国际象棋不能移动没有棋子的地方");

                      System.exit(0);

                   }*/

             }      

                 System.out.println("谢谢使用");

                 System.exit(0);

        }

        if(temp1==2)

        {

             System.out.println("是否要继续输入,结束输入end");

             System.out.println("input :");

             String endString=input.next();

            

             while(!endString.equals("end"))

             {

                   System.out.println("input x");

                   int x=input.nextInt();

                   System.out.println("input y");

                   int y=input.nextInt();

                   Position pos=new Position(x, y);

                   System.out.println("3 下棋");

                 System.out.println("4 吃子");

                 int choose=input.nextInt();

                 if(choose==3)

                 {

                    

                       

                         System.out.println("输入白子还是黑子");

                         String test=input.next();

                              myAction2.goadd(pos,test);

                          

                       

                        /*else

                        {

                            System.out.println("不能在有棋的地方下棋");

                            return;

                           

                        }*/

                 }

                   if(choose==4)

                   {

                       

                       

                              myAction2.goeat(pos);

                       

                   }

                   /*else {

                      System.out.println("不能在没有棋的地方吃子");

                      System.exit(0);

                 }*/

             }

        }

我的这个类用来设计实现UI交互,在每次输入时都会判断是否输入end停止。

 

12.3.3 ADT和主程序的测试方案

针对各个ADT写出对应于其中方法的测试样例,比如返回布尔值的方法就输入一个值,看看是否返回了自己预想的值。还有针对类中的变量都要测试是否在范围内。

比如要测试player类中的gamehistory不能是空。

12.4 Multi-Startup Set (MIT)

请自行设计目录结构。

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

13 实验进度记录

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

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

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

日期

时间段

计划任务

实际完成情况

2019.4.1

14:37-15:30

P1

写完vertex相关的类

2019.4.3

17:20-20:57

P1

写完

2019.4.4

P2

花了一天时间写完较为简单的P2

20194.5

17:01-21:36

P3

P3比较复杂,花了大量时间来完善接口和参数的调整,方法的重载。花费时间较长。未完成

2019.4.6

All day

P3

写完player piece position

2019.4.7

All day

P3

P3写完

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

遇到的难点

解决途径

构造器写成了方法

 

 

将返回值去掉

参数与想要的方法不匹配

 

 

进行参数向上转型并且进行方法的重载。

总是进不去.size循环

 

 

发现没有初始化

接口对应不上

重新写了一个接口

15 实验过程中收获的经验、教训、感想

15.1 实验过程中收获的经验和教训

收获了对ADT和继承的更深入的理解,下次我将更为仔细的构造程序的底层,力争方法最简单,靠组合实现功能。

这次类写的太复杂,写到后面都忘记关系了。

15.2 针对以下方面的感受

(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)   《软件构造》课程进展到目前,你对该课程有何体会和建议?

 

 

面向对象编程我感到自己不是在写程序而是在搭建程序。但是不如面向过程的直接。我个人感觉还好,这种思想慢慢的被我接受。复用的函数给程序带来了可扩展性,个人感觉P3还是不利于新手入手,理解并融会贯通需要一段的时间。

posted @ 2019-11-26 16:30  heisse  阅读(433)  评论(0编辑  收藏  举报