[英]Immutability and Graphs Models - How to create them?
我將使用示例,因為它更容易顯示我想要做的事情。 我有三個類X,Y和Z,我希望能夠將它們作為不可變對象。 他們來了。
X級:
public class X{
private int id;
private String dataX;
private Collection<Y> collectionOfY;
private Collection<Z> collectionOfZ;
/* Constructors */
/* Getters */
/* "with" functions */
}
Y級:
public class Y{
private int id;
private String dataY;
private Collection<X> collectionOfX;
private Collection<Z> collectionOfZ;
/* Constructors */
/* Getters */
/* "with" functions */
}
Z級:
public class Z{
private int id;
private String dataZ;
private Collection<X> collectionOfX;
private Collection<Y> collectionOfY;
/* Constructors */
/* Getters */
/* "with" functions */
}
因此它們彼此鏈接並形成具有循環結構的圖形。 如果可能的話我想擁有不可變對象。 我已經實現了“With”函數,這些函數只發送一個屬性就會發回一個給定對象的副本。
但是,如果我實現完全不變性,我可能會復制鏈接(直接或間接)到我更改的對象的每個數據:更改“dataZ”通常意味着我想用新創建的對象替換舊對象鏈接的X和Y.由於變化等原因將被復制...
另一個解決方案是渲染集合,這三個類不是不可變的(並且只有部分不變性),但后來我幾乎失去了嘗試不變的所有興趣。
有人有個好主意嗎? 還是我要求不可能的? 我應該回到舊的setter(即使它意味着更復雜的並發管理)?
提前致謝 ;)
C#能夠通過內置的Lazy<T>
解決這個問題。 Lazy
是一個尚未計算其實際值的對象 - 在構造Lazy
,將工廠函數作為參數傳遞。
您可以使用Value
屬性向Lazy
詢問其值。 如果工廠函數已經運行,則返回已構造的值。 如果工廠功能尚未運行,則此時將運行。 無論如何, Value
屬性的返回始終是相同的。 一旦確定了一個特定的Lazy
的價值,它就會堅持下去。
惰性是對可能尚未構造的對象的不可變引用。 它在內部使用可變性,但從外部看,它似乎是不可變的。
在您的情況下,如果您的Java等效於Lazy
,則可以將集合從Collection<Y>
更改為Collection<Lazy<Y>>
。 這將使X的實例能夠引用一些尚未構造的Y實例。構造X
s, Y
s和Z
s的代碼不會直接構建這些實例,而是構建Lazy
實例。 這些實例將工廠函數作為參數; 反過來,這些工廠函數需要引用一些Lazy
值。 這意味着,在構造和連接這些東西的函數的上下文中,您需要對Lazy實例進行可變引用。
要明白我的意思,如果你試圖創建一個兩個對象的循環(我不完全掌握Java 8,所以我可能有語法錯誤):
Lazy<X> a;
Lazy<Y> b;
a = new Lazy<X>(() -> {
List<Y> ys = new ArrayList<Y>();
ys.add(b.getValue());
return new X(ys);
});
b = new Lazy<Y>(() -> {
List<X> xs = new ArrayList<X>();
xs.add(a.getValue());
return new Y(xs);
});
在實踐中,我認為這不會起作用。 我認為封閉變量需要在Java中是最終的(在C#中不是這種情況)。 所以我認為你需要實際做到這一點:
final Lazy<X>[] a = new Lazy<X>[1];
final Lazy<Y>[] b = new Lazy<Y>[1];
a[0] = new Lazy<X>(() -> {
List<Y> ys = new ArrayList<Y>();
ys.add(b[0].getValue());
return new X(ys);
});
b[0] = new Lazy<Y>(() -> {
List<X> xs = new ArrayList<X>();
xs.add(a[0].getValue());
return new Y(xs);
});
這是有效的,因為不會立即評估兩個lambda。 只要在執行這些lambda之前a[0]
和b[0]
設置為有效值,一切都會正常工作。
請注意,這使用了可變性,但在非常有限的范圍內具有可變性。 Lazy
實例中存在可變性,但這些實例似乎是不可變的。 在連線功能中存在可變性,但該功能將在前面運行並終止,而構造的對象可以存活更長時間。 至少在我看來,這種受約束的可變性是可接受的權衡。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.