HIT 软件构造 LAB2

目录

 

 

1 实验目标概述

2 实验环境配置

3 实验过程

3.1 Poetic Walks

3.1.1 Get the code and prepare Git repository

3.1.2 Problem 1: Test Graph <String>

3.1.3 Problem 2: Implement Graph <String>

3.1.3.1 Implement ConcreteEdgesGraph

3.1.3.2 Implement ConcreteVerticesGraph

3.1.4 Problem 3: Implement generic Graph<L>

3.1.4.1 Make the implementations generic

3.1.4.2 Implement Graph.empty()

3.1.5 Problem 4: Poetic walks

3.1.5.1 Test GraphPoet

3.1.5.2 Implement GraphPoet

3.1.5.3 Graph poetry slam(输入和数据库均采用的是题目说明中提供的样例)

3.1.6 Before you’re done

3.2 Re-implement the Social Network in Lab1

3.2.1 FriendshipGraph类

3.2.2 Person类(实际上经过本实验的修改后,只调用了构造方法,所以就不列出各个方法了)

3.2.3 客户端main()

3.2.4 测试用例

3.2.5 提交至Git仓库

4 实验进度记录

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

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

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

6.2 针对以下方面的感受

  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. 实验环境配置

本次实验需要安装EclEmma,直接在Eclipse Marketplace中搜索安装

HIT 软件构造 LAB2

遵循引导即可完成。

 

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

https://github.com/ComputerScienceHIT/HIT-Lab2-1190201003

  1. 实验过程

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

    1. Poetic Walks

这一部分给出了一个Graph的接口。要求编写ConcreteEdgesGraph和ConcreteVerticesGraph两个Graph的实现类,并且编写相应的测试类。在实现过程中,要自行编写规约。

      1. Get the code and prepare Git repository

按照实验手册提供的url,在本地打开git bash,使用git clone命令将远端仓库克隆到本地,以此获取代码。

      1. Problem 1: Test Graph <String>

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

3.1.2.1 实现GraphInstanceTest类

 

     1. testAdd()

思路:按add的规约,按点的等价类划分即可

      2. testSet()

思路:按照set的规约,需要对于权值的大小进行等价类划分,并且对于边是否存在也要进行测试

     3. testRemove()

思路:按remove的规约,按点的等价类划分即可

 

 

    4. testVertices()

思路:按Vertices的规约,按点的等价类划分即可

 

 

    5. testSources()

HIT 软件构造 LAB2

 

    6. testTargets()

HIT 软件构造 LAB2

 

结果:只做到这一步其实还不能运行该测试类,因为emptyInstance()还没有实现。完成了后续的工作后,可以得到以下结果

 

HIT 软件构造 LAB2

HIT 软件构造 LAB2

     3.1.3Problem 2: Implement Graph <String>

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

​​​​​​​    3.1.3.1Implement ConcreteEdgesGraph

3.1.3.1.1 实现Edge类

为了实现ConcreteEdgesGraph类,首先得实现作为边的Edge类

field:

要构造一个边,需要有起点,终点和权值,因此field由source,target和weight构成:

AF,RI等:

    // Abstraction function:

    //   AF(source)为边的起点

//   AF(target)为边的终点

//   AF(weight)为边的权值

    // Representation invariant:

    //   weight为正整数

//   source和target不为空

    // Safety from rep exposure:

//   source,target和weight设置为了private

//   source,target和weight在返回时采用了防御式拷贝

 

构造方法:

构造方法根据起点,终点和权值来初始化一条边即可;

 

checkRep:

作用:检查RI;

思路:根据所编写的RI依次进行检查即可;

getSource:

返回边的起点;

 

getTarget:

返回边的终点;

 

getWeight:

返回边的权值;

 

toString:

功能:返回边的字符串;

思路:为了方便阅读,采取了“起点--权值->终点”的形式;

3.1.3.1.2 完成ConcreteEdgesGraph类(add,set等方法的规约和Graph接口中完全相同,在报告中不再重复)

 

根据要求,写出AF,RI等:

    // Abstraction function:

    //  AF(vertices)是图中的所有点

    //  AF(edges)是图中的所有边

    // Representation invariant:

    //  所有点都存在于vertices中

    //  所有边都存在于edges中

    //  权值必须为正整数

    // Safety from rep exposure:

    //  vertices和edges都设置为private类型

 //  vertices在返回时使用了防御式拷贝

 

filed:

要构造一个图,需要一个边集合,一个点集合:

构造方法:

直接采取缺省的构造方法

checkRep:

作用:检查RI;

思路:根据所写的RI,逐项进行检查即可;

add:

作用:将一个点加入图中;

思路:检查该点是否在图中。已有的点返回false,新的点加入vertices;

 

set:

作用:将一条新的边加入图中,或者更新一条已有的边的权值,或者移除一条边;

思路:检查weight的值。如果小于0,返回-1;如果等于0,移除该边;如果大于0,将此边加入图中,或者更新该边的权值(取决于这是否是新的边);

实现:以下为weight大于0的情况:采用迭代器来检查是否是新的边,对于需要更新的情况,先移除原边,再加入新的边即可;

 

 

remove:

作用:移除一个点,以及和它有关的边;

思路:检查图中是否存在这个点;如果存在,则移除;如果不存在,返回false;

实现:需要注意的是,以被移除点作为起点和作为终点的边均要移除;

 

vertices:

作用:返回点集合;

实现:采取防御式拷贝

 

 

sources:

作用:返回<起点,权值>构成的map;

思路:构造一个空的map,遍历边集合,将和target匹配的<起点,权值>加入map中即可;

 

target:

作用:返回<终点,权值>构成的map;

思路:同8;

 

 toString:

作用:返回图的字符串;

思路:依次返回每条边的字符串;

3.1.3.1.3 实现ConcreteEdgeGraphTest类

本测试类只需要测试Edge中的方法,其他的方法都在GraphInstanceTest中测试了。

1. testConcreteEdgesGraphtoString():

 

 

  1. testEdgeGetSource():

 

 

  1. testEdgeGetTarget():

 

 

  1. testEdgeGetWeight():

 

 

测试结果:

HIT 软件构造 LAB2

    ​​​​​​​3.1.3.2Implement ConcreteVerticesGraph

3.1.3.2.1 实现Vertex类

要利用点来构成图,首先要先实现一个表示点的类Vertex

field:

每个点都有一个指向该点的起点集,一个该点指向的终点集以及作为点的标识的名字。集合采用<L, Integer>构成的map来表示,这样还可以记录下权值:

 

AF,RI等:

    // Abstraction function:

    //   AF(name)为点的名字

//   AF(sources)为所有指向该点的点以及对应边的权值

//   AF(targets)为所有该点指向的点以及对应边的权值

    // Representation invariant:

    //   所有点均不为空

//   所有权值均大于0

    // Safety from rep exposure:

    //   name,sources,targets均设置为private

//   返回时采用防御式拷贝

 

构造方法:

按照点的名字进行点的初始化

 

 

checkRep:

作用:检查RI;

 

 

getName:

作用:返回点的名字;

 

getSources:

作用:返回<起点,权值>构成的起点表;

 

getTargets:

作用:返回<终点,权值>构成的终点表;

 

addSource:

作用:在起点表中移除或者加入或者更新一个起点,便于之后实现ConcreteVerticesGraph类中的set方法;

思路:类似set方法。其中移除通过后续编写的removeSource来实现,加入新的点或者更新通过HashMap提供的put方法实现;

 

addTarget:

作用:在终点表中移除或者加入或者更新一个终点,便于之后实现ConcreteVerticesGraph类中的set方法;

思路:同8;

 

 removeSource:

作用:在起点表中删去一个起点;

思路:通过HashMap提供的remove方法实现。不过由于remove方法返回的是Integer,本方法的实际目的是将Integer转化成int。在Integer不是null的情况下,可以将Integer直接赋给int,所以当remove返回null时,我们需要返回0;

 

 removeTarget:

作用:在终点表中删去一个终点;

思路:同10;

 

hashCode和Equals方法直接通过eclipse提供的插件来实现;

3.1.3.2.2 实现ConcreteVerticesGraph类(add,set等方法的规约和Graph接口中完全相同,在报告中不再重复)

 

field:本实现类是基于点来实现的,所以需要一个表示所有点的集合。为了便于检查RI,所以采用了List,而不是Set。

 

 

AF,RI等:

    // Abstraction function:

    //   AF(vertices)为图中所有的点

    // Representation invariant:

    //   vertices中的点不可重复

    // Safety from rep exposure:

    //   vertices设置为private类型

//  vertices在返回时使用了防御式拷贝

 

构造方法:

直接采用缺省的构造方式进行初始化;

 

checkRep:

作用:检查RI;

 

 

add:

作用:在图中加入一个新的点;

思路:通过name来判断该点是否是在图中。如果是已有的点,返回false;如果是新的点,通过name来初始化一个新的Vertex,然后加入图中;

 

set:

作用:将一条新的边加入图中,或者更新一条已有的边的权值,或者移除一条边;

思路:通过Vertex类中的addSource和addTarget方法就很容易实现;

 

remove:

作用:移除图中的一个点,以及和这个点相关的边;

思路:遍历图中的点。如果是该点,则移除;如果是该点的起点,则调用removeTarget方法;如果是该点的终点,则调用removeSource方法;

以下是每次遍历需要执行的内容:

 

vertices:

作用:返回点集合;

思路:由于vertices是List,所以需要再建立一个Set,依次加入点

实现:采取防御式拷贝

 

 

sources:

作用:返回<起点,权值>构成的map;

思路:返回指定点的起点表即可;

 

target:

作用:返回<终点,权值>构成的map;

思路:同8;

 

 toString:

作用:返回图的字符串;

思路:依次返回每条点的字符串;

3.1.3.1.3 实现ConcreteVerticesGraphTest类

 

只需要测试Vertex类中的方法。

 

testConcreteVerticesGraphtoString:

 

 

testGetName:

 

 

testGetSources:

 

 

testGetTargets:

 

 

testAddSource:

思路:按照规约,需要分别就点的等价类和权值的等价类进行划分;

 

 

testAddTarget:

 

 

testRemoveSource:

 

 

testRemoveTarget:

 

 

testEquals:

思路:要测试点是否相等,需要考察起点表,终点表和名字;

 

测试结果如下:

HIT 软件构造 LAB2

3.1.4 Problem 3: Implement generic Graph<L>

3.1.4.1 Make the implementations generic

将所有之前使用String实现的地方全部修改为泛型实现,然后根据eclipse的语法错误提醒来完成所有的修改;

​​​​​​​3.1.4.2 Implement Graph.empty()

选择一个具体的实现类就行了。这里选择的是使用ConcreteEdgesGraph。

 

补充了对于String,Integer,Float,Character这四种具体类型的测试;

这里的测试策略是利用Collection来创建一个空Set,然后测试empty方法是否也能正常生成一个空Set。

HIT 软件构造 LAB2

 

至此,已经完成了Graph的两个具体实现类的泛型实现以及测试类。

以下是所有的测试和覆盖率结果;

HIT 软件构造 LAB2

HIT 软件构造 LAB2

 

 

其中GraphInstanceTest类的测试结果已经包含在实现类的测试中。

 

 

上一篇:HIT 自动预约游泳馆等资源


下一篇:HIT软件构造第三章