graphs可变与不可变
Mutable and Immutable graphs
可变的类型
MutableGraph,MutableValueGraph,MutableNetwork
删除和添加节点
addNode(node)
removeNode(node)
添加和删除边
putEdge(nodeU,nodeV)
removeEdge(nodeU,nodeV)
putEdgeValue(nodeU,nodeV,value)
removeEdge(nodeU,nodeV)
addEdge(nodeU,nodeV,value)
removeEdge(edge)
这是与ava集合框架相互背离的,在guava的新集合类上有这些方法,有一定历史原因的,这些方法上都有可变签名,我们试着打破这种可变方法
来满足防御式编程,一般来说,你的方法仅仅是检查而不是去修改图,这些入参在Graph,ValueGraph,Network上应该指定,而不是在它们的子类型指定,
换句话说,如果你的代码需要修改一个对象,那么有一个可修改标签会更明显。
graph,虽然不包含可变的方法,也可能通过调用其他的接口去修改,如果想要提供一个契约性的方法保证参数是不可变的或者返回值是不可变的,那么就应该实现Immutable。
Immutable*的实现
每个graph类型都有Immutable实现,这些类和guava的Immutableset.immutableList,immutableLIst,ImmutableMap类似,一旦构造完成,不能修改,最终使用的不可变数据结构和其他的Immutabe类型不同,这些实现在可变方法上没有任何方法签名,不需要对修改对象的调用抛出UnsupportedOperationException
创建不可变的ImmutableGraph
调用copyof()方法
保证点:
浅拷贝不可变 元素不能被甜,移除,替换
- 确定的迭代顺序:迭代的顺序总是和加入graph的顺序一样
- 线程安全:多个线程同时访问graph结构时候是安全的
- 完整:这种类型在包的外面是不能创建子类的
将这种类看作接口,而不是实现,每一个不可变的类,提供一个有意义的行为保证,不仅仅是一个特殊的实现,在每一个重要的场景中将它们视为接口
类中的方法和属性返回的值存储在Immutable*的实例中,如ImmutableGraph应该被定义成一个Immutable*的类型而不是一个相应的接口类型,如graph对于调用者在上述语义的保证,是非常重要的信息;
另一方面,参数中使用ImmutableGraph对调用者而言是一个很讨厌的方法,而是使用相应的Graph接口
图中的元素(点和边)
元素经常被当作一个map的健唯一性,如何两个元素完全一致,那么其中只有一个能成为graph的元素
hashCode()和equals()方法的一致性,hashcode()必须和equals()一致当调用Object.hashCode()方法
equals()方法顺序的一致性如果节点已经排过序,顺序应该和Comparator或Comparable中equals方法一致
非递归:hashCode和equals()和其他元素之间必须是非递归的,如下所示
public final class Node<T> {
T value;
Set<Node<T>> successors;
public boolean equals(Object o) {
Node<T> other = (Node<T>) o;
return Objects.equal(value, other.value)
&& Objects.equal(successors, other.successors);
}
public int hashCode() {
return Objects.hashCode(value, successors);
}
}
使用这样的common.graph 元素类型有一下的问题:
递归:common.graph类库提供的graph的实现存储了这些关系
无效:添加访问这些元素调用equals()方法需要O(n)的时间复杂度
不可行性:如果在图中有环,equals和hashCode()不会终止
元素和可变状态
如果图的元素有可变的状态
1.可变的状态不应该在equals()/hashCode()方法中被调用
2.不要构建多个相同的元素,期望他们能够相互替代
如果想要存粗可变的每个元素状态,一个选择就是使用不可变的元素,并且把可变的状态保存在不同的数据结构中
元素必须是非空将元素添加到图中的时候需要合约上拒绝这种元素
类库中的约定和行为
commom.graph类型的内部实现
可变
将不存在的两个顶点上加一条边也会成功,默认将这两个顶点加到图中
graph中equals方法和equivalance
在guava22中,common.graph的方法中定义了equals()
对于特定类型有特定的方法
graph。equals()定义了两个graph相等,如果有相同的顶点和边集合
ValueGraph.equals()定义了两个ValueGraph相等
如果有相同的顶点和边集合
Network.equals()方法,定两个network相等,如果有相同的顶点和边集合此外,每一个图类型,两个图相同边的方向是一致的
同样,hashcode()方法与equals()方法对于每个图类型保持一致
如果想要比较两个Network和两个ValueGraph基于连通性,或者比较Network,ValueGraph和graph,可以使用network和ValueGraph提供的Graph视图