我正在为客户构建一个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
我需要能够按名称访问各种数据元素,例如:
Elements.Earth.Name
Elements.Water.Physical.Color
我还需要能够遍历属性,如:
for (MagicalType attrib : Elements.Fire.Magical)
{
...
}
我实际上已经能够创建这个数据结构了,我可以做我上面要求的所有事情 - 尽管我必须为迭代创建单独的数组,所以我真的看起来更像是:
for (MagicalType attrib : Elements.Fire.MagicalAuxArray)
不幸的是,我无法满足我的最后要求:整个数据结构必须是不可变的。我已经反复尝试过,并在网上搜索示例,但到目前为止,我还没能以任何合理的方式完成此任务。请注意,最终的数据结构将非常大;我真的希望避免过于重复的解决方案或创建过多的公共符号。
我是一名非常有经验的程序员,对Java不太熟悉。任何人都可以建议我如何代表上述数据以满足我的所有要求吗?
答案 0 :(得分:6)
立即浮现在脑海中的几种方式:
List
而不是数组。这样您就可以return new ArrayList<MagicalType>(MagicalAuxList)
代替return MagicalAuxList
。这样,使用该类的人将无法修改该集合。一点需要注意。如果您的数组包含复杂对象,它们也必须是不可变的。unmodifiableCollection
静态方法(对于列表,集合等有类似的静态方法 - 使用适合您的方法)在您返回时转换您的集合它。这是防御性复制的替代方案。答案 1 :(得分:1)
为什么使用数组?不可变的集合(例如来自Google Guava)是否会做得更好?
答案 2 :(得分:0)
您可以在公共API中使用Iterable
。使用所有需要抑制的变异器来清除收藏。 (遗憾的是Iterator
有一个remove()
方法(?!),但那只是一个)
public final Iterable<MagicalType> magics;
for(MagicalType magic : magics) ...
答案 3 :(得分:0)
你可以尝试使用final,enums和unmodifiable maps的下面的代码。但是这不允许您按名称访问,因为您需要从地图中获取。你可以在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;
}