簡體   English   中英

不變性和圖形模型 - 如何創建它們?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM