[英]How to build a complex, hierarchic immutable data structure in Java?
I'm building a Java library for a customer, and one of the things they want is a data representation of a particular set of standards they work with. 我正在为客户构建一个Java库,他们想要的东西之一就是他们使用的一组特定标准的数据表示。 I don't want to reveal my customer's interests, but if he were an alchemist, he might want the following:
我不想透露客户的利益,但如果他是炼金术士,他可能会想要以下内容:
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
I need to be able to access various data elements by name, such as: 我需要能够按名称访问各种数据元素,例如:
Elements.Earth.Name
Elements.Water.Physical.Color
I also need to be able to iterate through attributes, as: 我还需要能够遍历属性,如下所示:
for (MagicalType attrib : Elements.Fire.Magical)
{
...
}
I have actually been able to create this data structure, and I can do everything I've asked for above -- though I had to create separate arrays for the iteration, so really what I do looks more like: 我实际上已经能够创建这个数据结构了,我可以做我上面要求的所有事情 - 虽然我不得不为迭代创建单独的数组,所以我真的看起来更像是:
for (MagicalType attrib : Elements.Fire.MagicalAuxArray)
Unfortunately I haven't been able to meet my last requirement: the entire data structure must be immutable. 不幸的是,我无法满足我的最后要求:整个数据结构必须是不可变的。 I have tried repeatedly, and scoured the web looking for examples, but so far I haven't been able to accomplish this in any reasonable manner.
我已经反复尝试过,并在网上搜索示例,但到目前为止,我还没能以任何合理的方式完成此任务。 Note that the final data structure will be quite large;
请注意,最终的数据结构将非常大; I'm really hoping to avoid a solution that is too repetitious or creates too many public symbols.
我真的希望避免一个过于重复或创造太多公共符号的解决方案。
I am a very experienced programmer, less experienced with Java. 我是一名非常有经验的程序员,对Java不太熟悉。 Can anyone suggest how I might represent the above data to meet all my requirements?
任何人都可以建议我如何代表上述数据以满足我的所有要求吗?
A few ways that come to mind immediately: 立即浮现在脑海中的几种方式:
List
instead of an array. List
而不是数组。 That way you can do return new ArrayList<MagicalType>(MagicalAuxList)
instead of return MagicalAuxList
. return new ArrayList<MagicalType>(MagicalAuxList)
而不是return MagicalAuxList
。 This way people who use the class won't be able to modify the collection. unmodifiableCollection
static method (there are similar static-methods for lists, sets, etc. - use whichever one is appropriate for you) to convert your collection when you return it. unmodifiableCollection
静态方法(对于列表,集合等有类似的静态方法 - 使用适合您的任何一种)在您返回时转换您的集合。 This is an alternative to defensive copying. Why do you use arrays? 为什么使用数组? Wouldn't immutable collections (eg from Google Guava ) do a better job?
不可变的集合(例如来自Google Guava )不会做得更好吗?
You can use Iterable
in your public API. 您可以在公共API中使用
Iterable
。 Cleaner than Collections with all the mutators that you have to suppress. 使用所有需要抑制的变异器来清除收藏。 (unfortunately
Iterator
has a remove()
method(?!) but that's just one) (遗憾的是
Iterator
有一个remove()
方法(?!),但那只是一个)
public final Iterable<MagicalType> magics;
for(MagicalType magic : magics) ...
you could try the code below that uses final, enums and unmodifiable maps. 您可以尝试使用final,enums和unmodifiable maps的下面的代码。 but that does not let you access by name since you need to do a get from the map.
但是这不允许您按名称访问,因为您需要从地图中获取。 you could probably do that in groovy.
你可以在groovy中做到这一点。
import java.util.*;
enum Color {
red, green, blue;
}
class Physical {
Physical(final Double temperature, final Color color) {
this.temperature = temperature;
this.color = color;
final Map<String, Object> map=new LinkedHashMap<String, Object>();
map.put("temperature", temperature);
map.put("color", color);
this.map=Collections.unmodifiableMap(map);
}
final Double temperature;
final Color color;
final Map<String, Object> map;
}
class Magical {
Magical(final String domain, final Integer ordinality) {
this.domain = domain;
this.ordinality = ordinality;
final Map<String, Object> map=new LinkedHashMap<String, Object>();
map.put("domain", domain);
map.put("ordinality", ordinality);
this.map=Collections.unmodifiableMap(map);
}
final String domain;
final Integer ordinality;
final Map<String, Object> map;
}
public enum Elements {
earth("Earth", new Magical("Stability", 1), null), air("Air", null, null), fire("Fire", new Magical("Strength", null), new Physical(451., Color.red)), water(
"Water", null, new Physical(null, Color.blue));
Elements(final String name, final Magical magical, final Physical physical) {
this.name = name;
this.magical = magical;
this.physical = physical;
}
public static void main(String[] arguments) {
System.out.println(Elements.earth.name);
System.out.println(Elements.water.physical.color);
for (Map.Entry<String, Object> entry : Elements.water.physical.map.entrySet())
System.out.println(entry.getKey() + '=' + entry.getValue());
for (Map.Entry<String, Object> entry : Elements.earth.magical.map.entrySet())
System.out.println(entry.getKey() + '=' + entry.getValue());
}
final String name;
final Magical magical;
final Physical physical;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.