Java 不变性和图形模型-如何创建它们?

Java 不变性和图形模型-如何创建它们?,java,data-structures,graph,architecture,immutability,Java,Data Structures,Graph,Architecture,Immutability,我将使用示例,因为它更容易显示我想要做什么。我有三个类X、Y和Z,我希望能够将它们作为不可变对象。给你 X类: public class X{ private int id; private String dataX; private Collection<Y> collectionOfY; private Collection<Z> collectionOfZ; /* Constructors */ /* Getter

我将使用示例,因为它更容易显示我想要做什么。我有三个类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 */

}
公共类X{
私有int-id;
私有字符串dataX;
私人收藏;
私人收藏;
/*建设者*/
/*吸气剂*/
/*“带”功能*/
}
Y类:

public class Y{

    private int id;
    private String dataY;

    private Collection<X> collectionOfX;
    private Collection<Z> collectionOfZ;

    /* Constructors */
    /* Getters */
    /* "with" functions */

}
公共类Y{
私有int-id;
私有字符串数据;
私人收藏外汇;
私人收藏;
/*建设者*/
/*吸气剂*/
/*“带”功能*/
}
Z类:

public class Z{

    private int id;
    private String dataZ;

    private Collection<X> collectionOfX;
    private Collection<Y> collectionOfY;

    /* Constructors */
    /* Getters */
    /* "with" functions */

}
公共类Z{
私有int-id;
私有字符串dataZ;
私人收藏外汇;
私人收藏;
/*建设者*/
/*吸气剂*/
/*“带”功能*/
}
因此,它们相互联系,形成一个具有循环结构的图。如果可能的话,我想要不可变的对象。我已经实现了“With”函数,它将只更改一个属性就发回给定对象的副本

但是,如果我实现了完全不变性,我可能会导致(直接或间接)链接到我更改的对象的每个数据的复制: 更改“dataZ”通常意味着我想用链接X和Y中新创建的对象替换旧对象。由于更改等原因,这些对象将被复制

另一个解决方案是使链接这三个类的集合不是不可变的(并且只有部分不可变),但是我几乎失去了尝试具有不可变性的所有兴趣

有人有好主意吗?还是我在要求不可能的事情?我是否应该回到旧的setter(即使它意味着更复杂的并发管理)

提前感谢;)

C#能够通过其内置的
Lazy
解决这个问题。
Lazy
是一个尚未计算其实际值的对象-在构造
Lazy
时,将工厂函数作为参数传递

您可以使用
value
属性询问
Lazy
的值。如果工厂函数已运行,则返回已构造的值。如果factory函数尚未运行,则此时它将运行。无论何种情况,
属性的返回总是相同的。一旦确定了一个特定的
惰性
值,它就会保持不变

lazy是对可能尚未构造的对象的不可变引用。它在内部使用易变性,但从外部看,它似乎是不可变的

在您的例子中,如果您有一个相当于
Lazy
的Java,那么您可以将您的集合从
Collection
更改为
Collection
。这将使X的实例能够引用一些尚未构造的Y的实例。而构造
X
s、
Y
s和
Z
s的代码不会直接构建这些实例,而是构建
Lazy
的实例。这些实例将工厂函数作为参数;反过来,这些工厂函数需要引用一些
Lazy
值。这意味着,在构建和连接这些东西的函数的上下文中,需要对惰性实例进行可变引用

为了理解我的意思,如果您尝试创建一个由两个对象组成的循环(我不完全熟悉Java 8,所以可能会有语法错误):

a;
懒惰的b;
a=新懒惰(()->{
List ys=新的ArrayList();
ys.add(b.getValue());
返回新的X(ys);
});
b=新的惰性(()->{
List xs=new ArrayList();
添加(a.getValue());
返回新的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);
});
final Lazy[]a=新的Lazy[1];
final Lazy[]b=新Lazy[1];
a[0]=新的惰性(()->{
List ys=新的ArrayList();
添加(b[0].getValue());
返回新的X(ys);
});
b[0]=新的延迟(()->{
List xs=new ArrayList();
添加(a[0].getValue());
返回新的Y(xs);
});
这是因为两个lambda没有立即进行评估。只要在执行这些lambda之前将
a[0]
b[0]
设置为有效值,一切都会正常工作


注意,这使用了可变性,但在非常有限的范围内使用了可变性。
Lazy
实例中存在可变性,但这些实例似乎是不可变的。wire-up函数具有易变性,但该函数将提前运行并终止,而构造的对象可以存活更长的时间。至少对我来说,这种受约束的易变性是一种可以接受的权衡。

所以你想让任何人都不能修改对象吗?或者可以创建但无法修改属性?
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);
});