Guava -可變和不可變的graphs
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檢視