有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何操作不可变对象树?

我正在用不可变的对象构建一个完整的应用程序,这样多线程和撤销就更容易实现了。我正在使用Google Collections Library,它提供了Map、List和Set的不可变版本

我的应用程序模型看起来像一棵树:

  • 场景是包含对根节点的引用的顶级对象
  • 每个节点都可以包含子节点和端口

对象图可能如下所示:

Scene
 |
 +-- Node
      |
      +-- Node 
           |
           +- Port
      +-- Node
           |
           +- Port
           +- Port

如果所有这些对象都是不可变的,由顶级SceneControl对象控制:

  • 构建此层次结构的最佳方法是什么
  • 如何替换对象树中任意深度的对象
  • 是否有办法支持反向链接,例如具有“父”属性的节点

更一般地说:

  • 是否出现了处理此类数据的模式
  • 有关于这个主题的(学术)文献吗
  • 这是个好主意吗

共 (2) 个答案

  1. # 1 楼答案

    这里有两个有趣的概念。首先,持久数据结构。如果树的所有元素都是不可变的,则可以通过替换某些部分(但引用旧部分)从原始树派生新树,从而节省时间和内存

    例如,如果要向已具有两个端口的节点添加第三个端口,则必须创建新场景、新场景的节点的子体以及要更改的节点。不需要重新创建其他节点和所有端口,只需在新场景/节点中引用它们即可

    另一个概念是拉链。拉链是一种通过持久数据结构“导航”以优化本地更改的方法。例如,如果添加了四个新端口而不是一个,但每次添加一个端口,则必须创建四个新场景和八个新节点。使用拉链,您可以将这些创建推迟到完成,从而节省中间对象的开销

    我读过的关于拉链最好的解释是here

    现在,使用拉链来导航数据结构就不需要反向链接了。通过巧妙地使用递归构造函数,您可以在一个不可变的结构中拥有反向链接。然而,这样的数据结构不会是持久的。非持久不变数据结构的修改性能很差,因为每次都需要复制整个数据

    至于学术文献,我推荐Okasaki(dissertation PDFfully fledged book)的纯函数数据结构

  2. # 2 楼答案

    如果你的树是不可变的,那么如果你想改变它,你必须生成一个新的树

    这听起来很糟糕,但并非所有节点都是不可变的!因为不需要复制不可变对象,所以除了所做的更改之外,新树将主要引用旧树

    您必须以这样一种方式设计树,即每个不可变树引用其他不可变树。这样,您也不需要复制整个不可变树

    但是如果你走不可变的树路线,那么你就不能有反向链接。否则就不能重用子树