软件构造lab2

        补发lab2实验报告,本次实验遇到了蛮多困难,解决得也不是特别好。

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

环境配置与Lab1相仿。此外,本次实验在 Eclipse IDE中安装配置 EclEmma(一个用于统计JUnit测试用例的代码覆盖度测试用例的代码覆盖度plugin)

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

  1. 实验过程

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

    1. Poetic Walks

分别建立两个类ConcreteEdgesGraph,ConcreteVerticesGraph 实现Graph接口。Graph接口要求实现add(添加新节点),set(添加新边),remove(移除节点),vertices(获得所有的节点集合),sources(target)获得以target为目标节点的边的起始节点,targes(source)获得以source为起始节点的边的目标节点。还要求将ADT泛型化。并且编写测试文件的时候,需要从实现的基本功能出发,有良好的测试覆盖率。

      1. Get the code and prepare Git repository

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

获取代码:访问Spring2021_HITCS_SC_Lab2/P1 at master rainywang/ Spring 2021_HITCS_SC_Lab2 (github.com)下载P1文件夹,获取任务代码。

git init 初始化仓库

touch.gitignore 创建ignore 文件,并且后面编辑该文件

git add. 将当前目录暂存

git commit -m “idea init”

git remote add origin 

git push origin master --force 强制覆盖远程分支

之后下载数据文件和已提供的代码,对应好目录之后再次提交推送

      1. Problem 1: Test Graph

将Graph empty()方法修改为

public static String Graph empty() {

                    return new ConcreteEdgesGraph<>();

    }

      1. Problem 2: Implement Graph
        1. Implement ConcreteEdgesGraph

1.Edge类:

// Abstraction function:

        // String source, target;

        // int weight;

        // Representation invariant:

        // source, target != null;

        // source != target;

        // weight >= 0;

其中source、target为不可变变量,使用防御式编程,故只提供gatter方法。而weight为可变变量,提供changeWeight方法来修改其值。

另外,实现构造函数及checkRep、toString方法。

2.ConcreteEdgesGraph类

private final Setvertices = new HashSet<>();

        private final List> edges = new ArrayList<>();

        // Abstraction function:

        // 顶点集vertices;边集edges

        // Representation invariant:

        // number of vertices >= 1;

        // number of edges >= 0;

        // 两点间最多一条边

        // Safety from rep exposure:

// use private final

具体方法:

1.add(L vertex):返回set中的add方法,即如果里面有相同点则返回false。

2.set(L source, L target, int weight):先判断vertices中是否有source和target,若没有,则加上(直接调用add方法即可实现)。然后遍历edges,寻找source到target的边,若找到,就更新此时的权值,并返回原先的值。遍历后判断若新输入的weight>0,则把set的参数制成的新边加入edges,否则删除原来的边。

3.remove(L vertex):若vertices中没有该点,直接返回false;若有,遍历edges,把与之相关的边全部删除,最后把vertices中该点删除。

4.Set vertices():返回vertices。

5.Map sources(L target):在edges中寻找所有目标点是target的初始节点(加权),逐一写入新的map中,返回最终对应键值对。

6.Map targets(L source):在edges中寻找所有目标点是source的初始节点(加权),逐一写入新的map中,返回最终对应键值对。

        1. Implement ConcreteVerticesGraph

1.Vertex类

      private final L name;

        private Mapsources = new HashMap();

        private Maptargets = new HashMap();

// Abstraction function:

        // 用vertices抽象的图,到图结构的映射

        // Representation invariant:

        // 不能重复、不为空

        // Safety from rep exposure:

        // private final

        // defensive copy

提供三个setter、getter方法,方便后续更改及调用。另外,实现构造函数及checkRep、toString方法。

2.ConcreteVertices类

private final List> vertices = new ArrayList<>();

// Abstraction function:

        // 用vertices点的集合抽象图的结构

        // Representation invariant:

        // 不重复

        // Safety from rep exposure:

        // private final

        // defensive copy

1.add(L vertex):先寻找vertices中的name有没有与vertex中相同,若没有返回false,若有将以vertex为name的新边加到vertices中,返回true

2.set(L source, L target, int weight):先判断vertices中是否有source和target,若没有,则加上;然后遍历vertices,寻找source和target点,若找到,就通过setTarget和setSource传入weight进行处理,返回两个函数的返回值

3.remove(L vertex):遍历vertices,将其中map的键中的vertex删除,若有vertices中name是vertex,将其删除,并返回true;若没有,返回false

4.Set vertices():遍历vertices,把每个name加到set中,最后返回set

5.Map sources(L target):遍历vertices,寻找name是target的点,通过 getSource返回他的map

6.Map targets(L source):遍历vertices,寻找name是source的点,通过 getTarget返回他的map

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

将具体类的声明更改为:

public class ConcreteEdgesGraph implements Graph { … }

class Edge { … }

public class ConcreteVerticesGraph implements Graph { … }

class Vertex { … }

使用占位符L代替,更新两个实现以支持任何类型的顶点标签String。粗略地说,您应该能够使用!查找和替换String代码中的所有实例L。这种重构将Concrete¬EdgesGraph,Concrete¬VerticesGraph,Edge,和Vertex泛型类型。

        1. Implement Graph.empty()

将Graph empty()方法修改为

public static Graph empty() {

                    return new ConcreteEdgesGraph<>();

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

    }

这里以ConcreteEdgesGraph作为Graph默认的实例类,也可以用ConcreteVerticesGraph,二者是等价的。

      1. Problem 4: Poetic walks
        1. Test GraphPoet
        2. Implement GraphPoet软件构造lab2

        1. Graph poetry slam
      1. 使用Eclemma检查测试的代码覆盖度

      1. Before you’re done

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

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

Git add .

Git commit -m “xxx”

Git push origin master

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


    1. 这个实验是基于在Poetic Walks中定义的Graph及其两种实现,重新实现Lab1中的 FriendshipGraph类。我们需要尽可能复用ConcreteEdgesGraph或 ConcreteVerticesGraph中已经实现的add()和set()方法,而不是从零开始。另外基于所选定的 ConcreteEdgesGraph 或 ConcreteVerticesGraph的rep来实现,而不能修改父类的rep。Re-implement the Social Network in Lab1
      1. FriendshipGraph

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

   private final ConcreteEdgesGraphgraph = new ConcreteEdgesGraph<>();

    // Abstraction function:

    //有向图构成的关系图

    // Representation invariant:

    //图中两点只有一条边,不存在自己到自己的边

    // Safety from rep exposure:

//属性采用private  final标签

1.public void addVertex(Person person) throws IllegalArgumentException:利用ConcreteEdgesGraph中已写好的add方法,向关系图中添加节点,如果图中已包含该节点抛出异常提示重名。

2.public void addEdge(Person p1, Person p2):调用ConcreteEdgesGraph中set方法设置有向边

3. public int getDistance(Person p1, Person p2):获取二人距离,具体是使用队列+深度优先搜索,如果两节点名字标签形同返回0;否则:distantMap保存其他人到Person1的距离

流程:入队自己,循环(出队,将其朋友全部入队,检查是否是Person2,不是加入distantMap,设置距离,是就返回)

4. public Set persons():调用graph.vertices()返回该关系图中所有节点拷贝的集合。

      1. Person

由于继承了ConcreteVerticesGraph,所以可以调用父类的rep和function,因此Person类就不需要过多的修饰和改动。

      1. 客户端main()

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

按照Lab1实验手册实现如下程序:

   public static void main(String[] args) {

       FriendshipGraphgraph = 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

    }

输出符合预期:

软件构造lab2

      1. 测试用例

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

测试用例与Lab1相同,但是注意换成Lab2的方法实现,例如:

软件构造lab2

而不是之前利用二维数组的形式。

测试结果如下:

软件构造lab2

      1. 提交至Git仓库

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

Git add .

Git commit -m “xxx”

Git push origin master

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

上一篇:[Git]Github代码版本管理


下一篇:开发中,常用git操作命令