我正在使用不可变对象(immutable对象)构建整个应用程序,以便更容易实现多线程和撤消。我正在使用 Google Collections Library它提供了不可变版本的 Map、List 和 Set。
我的应用程序模型看起来像一棵树:
- 场景是包含对根节点的引用的顶级对象。
- 每个节点都可以包含子节点和端口。
对象图可能如下所示:
Scene
|
+-- Node
|
+-- Node
|
+- Port
+-- Node
|
+- Port
+- Port
如果所有这些对象都是不可变的,由顶级 SceneController 对象控制:
- 构建此层次结构的最佳方式是什么?
- 如何替换对象树中任意深度的对象?
- 有没有办法支持反向链接,例如具有“父”属性的节点?
更一般地说:
- 是否出现了处理此类数据的模式?
- 是否有关于该主题的(学术)文献?
- 这是个好主意吗?
最佳答案
这里有两个有趣的概念。首先,持久数据结构。如果树的所有元素都是不可变的,那么可以通过替换一些部分从原始树派生出一棵新树,但引用较旧的部分,从而节省时间和内存。
例如,如果您要向已有两个端口的节点添加第三个端口,则必须创建一个新场景、一个新场景的节点后代以及您正在更改的节点。不需要重新创建另一个节点和所有端口——您只需在新场景/节点中引用它们即可。
另一个概念是 zipper 。 zipper 是一种通过持久数据结构“导航”以优化本地更改的方法。例如,如果您添加了四个新端口而不是一个,但您一次添加每个端口一个,则您必须创建四个新场景和八个新节点。使用 zipper ,您可以推迟此类创建直到完成,从而节省这些中间对象。
我读过的关于 zipper 的最好解释是 here .
现在,使用 zipper 来导航数据结构不再需要反向链接。通过巧妙地使用递归构造函数,您可以在不可变结构中拥有反向链接。但是,这样的数据结构不会持久。非持久不可变数据结构的修改性能很差,因为每次都需要复制整个数据。
至于学术文献,我推荐 Purely Function Data Structures,作者 Okasaki(dissertation PDF,fully fledged book)。
关于java - 如何操作不可变对象(immutable对象)树?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2586875/