软件构造实验二
本次实验的任务是实现一个图的接口Graph<L>,并使用该接口实现实验一中的FriendshipGraph及“写诗”
采用测试优先编程,故要先写测试策略。对Graph<String>的测试策略为:
1.add 加入不在图中的点、以在图中的点
2.set 边的起点是否在图中、终点是否在图中、权值是否为正数
3.remove 删除在图中的顶点及不在图中的顶点
4.vertices 图中有顶点/无顶点
5.sources 有邻接到该顶点的顶点/无邻接到该顶点的顶点
6.targets 该顶点邻接到其他顶点/不邻接到任何顶点
实现Graph<String>
1.实现ConcreteEdgesGraph
ConcreteEdgesGraph记录图的所有顶点和所有边。其中顶点为L(这里是String)型,边为Edge型。
Edge类定义如下:

toSring方法:

并设置相应的get方法。Edge是不可变的,故不提供set方法,且所有属性均为final
ConcreteEdgesGraph的实现:

add方法(添加顶点):

set方法(设置边的权值/添加边/删除边) 在更改边的权值时,由于Edge是不可变的。所以要删除原有的边并新建一条边

remove方法(删除顶点及关联的边):

vertices,sources和targets方法,其中vertices方法使用了防御式拷贝

toString方法:

ConcreteVerticesGraph为图的邻接表结构,Vertices类为顶点及其边表
Vertices类:

toString方法

并提供相应的get方法。同时由于Vertices是可变的,所以提供一定的set方法

ConcreteVerticesGraph类:

add方法

set方法


remove方法

vertices方法

sources和targets方法

toString方法

泛型化:将String改为类型参数L
“写诗”:GraphPoet类用于写诗,它包含一个Graph<String>类的属性graph来记录语料库中某个单词出现在另一个单词之后的次数。
在构造时将graph也一同初始化,每读入语料库中的一个单词,就尝试将其作为顶点加入图中,并将前一个单词对应的顶点到该顶点的边的权值加一。

“写诗”过程:将给定的句子写在字符串数组strings中,对每个单词strings[i],找在graph中存在strings[i]->s->strings[i+1]路径的“中间词”s,如果存在多个,则取weight(strings[i]->s)+weight(s->strings[i+1])
最大的单词s作为中间词插入strings[i]和strings[i+1]之间

用Graph<L>实现FriendshipGraph:
利用委派,将Graph<Person>作为FriendshipGraph的属性。

计算距离时采用实验一的方法。添加边时,默认每条边的权均为1.
对于Person类,则只需保留三个属性

其意义同实验一。并提供必要的get和set方法。
实验二相对于实验一,提出了关于安全性的要求。实验的过程中要时刻注意数据是否可变、是否出现表示泄露、检查表示不变性等问题。对于不可变的数据类型,则不能提供set方法,将属性设为private且引用不可变(final)。对于表示泄露的问题,可以考虑使用防御式拷贝。在编写程序的时候要注意写AF,RI和Safe from rep exposure并撰写checkRep方法。限于篇幅这里暂不赘述