本次实验训练抽象数据类型(ADT)的设计、规约、测试,并使用面向对象编程(OOP)技术实现 ADT。具体来说:
⚫ 针对给定的应用问题,从问题描述中识别所需的 ADT;
⚫ 设计 ADT 规约(pre-condition、post-condition)并评估规约的质量;
⚫ 根据 ADT 的规约设计测试用例;
⚫ ADT 的泛型化;
⚫ 根据规约设计 ADT 的多种不同的实现;针对每种实现,设计其表示(representation)、表示不变性(rep invariant)、抽象过程(abstractionfunction)
⚫ 使用 OOP 实现 ADT,并判定表示不变性是否违反、各实现是否存在表示泄露(rep exposure);
⚫ 测试 ADT 的实现并评估测试的覆盖度;
⚫ 使用 ADT 及其实现,为应用问题开发程序;
⚫ 在测试代码中,能够写出 testing strategy 并据此设计测试用例。
3.1 Poetic Walks
该任务需要我们构建一个Graph,实现spec中的基本功能,并将ADT泛型。
3.1.2 Problem 1: Test Graph
选择ConcreteEdgesGraph作为Graph的具体实现,将Graph中empty()方法改为:
测试结果:
3.1.3 Problem 2: Implement Graph
3.1.3.1 Implement ConcreteEdgesGraph
3.1.3.1.1 Edge类
设计思想:Edge类是边的类,包含字段的两个端点和边的权重。除了不可见性保护策略,还设计了不变量保护方法,选取的不变量为:weight>0.此外,除了get方法 ,还通过eclipse自带的工具生成相应的equals、hashcode、tostring方法
3.1.3.1.2 ConcreteEdgeGraph类
设计思想:set满足图中点和边不能重复的要求,只需要在checkRep中检查不重复性即可。
3.1.3.2 Implement ConcreteVerticesGraph
3.1.3.2.1 Vertex类
设计思想:Vertex类是点的类,包含四个字段,其中点的名字指向点与边的权重组成的Map。
其中的set等方法与ConcreteEdgeGraph中的类似。
3.1.3.2.2ConcreteVerticesGraph类
设计思想:将有向加权图描述为多个顶点,点与点之间的映射关系为边,其中变量尽可能定义为private和final
测试结果:
3.1.4 Problem 3: Implement generic Graph
3.1.4.1 Make the implementations generic
该任务需要将原文件按照要求修改为泛型。其中需要注意的是test也需要修改,但test不应为泛型,而是修改后泛型类的string实现。
3.1.4.1.1文件修改泛型
大略的意思就是使用占位符L代替String
3.1.4.1.2 Test类修改
修改为String类型的实现的test
测试结果:
3.1.4.2 Implement Graph.empty()
选择ConcreteEdgesGraph来使用和实施Graph.empty():
测试结果:
3.1.5 Problem 4: Poetic walks
3.1.5.1 Test GraphPoet
设计思路:构建一个语料库,然后根据输入作诗,判断是否与输出相同。
3.1.5.2 Implement GraphPoet
3.1.5.2.1 构造函数
逐行读入字符串行,然后存入一个字符串数组。再进行split分割等一系列处理。
3.1.5.2.2 作诗函数
首先将要作诗的输入字符串进行split分割,然后每一个字符串如果合法就加入。如果权重大于当前最大权重,就改变最大权重和最大权重对应的字符串即可。
测试结果:
3.1.5.3 Graph poetry slam
在原来的语料库中加入其它材料:
3.2 Re-implement the Social Network in Lab1
与Lab1中的实验课要求相同,只需使用P1中Graph类完成方法。我们需要尽可能复用ConcreteEdgesGraph或 ConcreteVerticesGraph中已经实现的add()和set()方法,而不是从零开始。另外基于所选定的 ConcreteEdgesGraph 或 ConcreteVerticesGraph的rep来实现,而不能修改父类的rep。
3.2.1 FriendshipGraph类
设计思路:继承ConcreteEdgesGraph,根据实验指导的提示,类中需要增加一些非法情况的判断,例如人已经存在,或者边已经存在等。
getDistance函数中最主要的就是找两个人距离的函数,因为根据题设要求最短距离,因此采用广度遍历的方式,此处需要用到Queue的数据结构,并且设置了一个List来存放已经访问过的person。
广度遍历的主要思路是:将P1进队,设置访问过,然后出队,依次调用this.targets()方法访问其相邻点,并且把它们进队,然后P1访问完再取队列第一个元素访问,直到某一相邻的点为P2则返回最短距离。如果所有点都访问完仍无最短距离,说明P1和P2没有关系,此时返回-1 。
3.2.2 Person类
与Lab1中相同。
3.2.3 客户端main()
设计思路:先new FriendshipGraph类,然后添加顶点和边,与Lab1相类似。