如何在Java中构建复杂的,层次结构的不可变数据结构?

vw-*_*ter 6 java

我正在为客户构建一个Java库,他们想要的东西之一就是他们使用的一组特定标准的数据表示.我不想透露客户的利益,但如果他是炼金术士,他可能会想要以下内容:

Elements
  Fire
    Name="Fire"
    Physical
      Temperature=451
      Color="Orange"
    Magical
      Domain="Strength"
  Water
    Name="Water"
    Physical
      Color="Blue"
  Earth
    Name="Earth"
    Magical
      Domain="Stability"
      Ordinality=1
Run Code Online (Sandbox Code Playgroud)

我需要能够按名称访问各种数据元素,例如:

  Elements.Earth.Name
  Elements.Water.Physical.Color
Run Code Online (Sandbox Code Playgroud)

我还需要能够遍历属性,如下所示:

  for (MagicalType attrib : Elements.Fire.Magical)
  {
    ...
  }
Run Code Online (Sandbox Code Playgroud)

我实际上已经能够创建这个数据结构了,我可以做我上面要求的所有事情 - 虽然我不得不为迭代创建单独的数组,所以我真的看起来更像是:

  for (MagicalType attrib : Elements.Fire.MagicalAuxArray)
Run Code Online (Sandbox Code Playgroud)

不幸的是,我无法满足我的最后要求:整个数据结构必须是不可变的.我已经反复尝试过,并在网上搜索示例,但到目前为止,我还没能以任何合理的方式完成此任务.请注意,最终的数据结构将非常大; 我真的希望避免一个过于重复或创造太多公共符号的解决方案.

我是一名非常有经验的程序员,对Java不太熟悉.任何人都可以建议我如何代表上述数据以满足我的所有要求吗?

Viv*_*ath 6

立即浮现在脑海中的几种方式:

  • 不要为对象提供setter方法.用户只能通过构造函数创建对象,一旦创建,就无法修改.这也适用于其他状态修改方法.如果要在构造函数中避免使用非常大的参数列表,可以使用Builder模式(在Joshua Bloch(第2版)中的Effective Java中描述)
  • 返回集合时,制作防御性副本.在这种情况下,使用a List而不是数组.这样你可以做return new ArrayList<MagicalType>(MagicalAuxList)而不是return MagicalAuxList.这样,使用该类的人将无法修改该集合.一点需要注意.如果您的数组包含复杂对象,则它们也必须是不可变的.
  • 对于不可变集合,您还可以尝试使用unmodifiableCollection静态方法(列表,集合等有类似的静态方法 - 使用适合您的任何一种)在您返回时转换您的集合.这是防御性复制的替代方案.