我知道我们已经对replacement of object instances提出了疑问,答案总是如此:即使你可以,也从不这样做,这是黑魔法,但我不知道如何解决我的问题,所以让我吧解释...
我正在解析有关某些车辆及其特定模块的数据,以存储在数据库中(这是关于游戏的)。每个Vehicle
都包含一些ComaptibleModules
:
class Vehicle {
String id;
// other stuff...
CompatibleModules modules;
}
ComaptibleModules
包含许多在Module
- 类(例如Engine extends Module
)中降序的对象,在复杂的框架中(依赖项和内容)。
class CompatibleModules {
Engine defaultEngine;
List<Engine> compatibleEngines;
// other stuff...
}
预计在此课程中会多次引用相同的Module
。
我只是按每辆车获取数据,因此即使某些车辆共享相同的模块(他们过度执行),我也会为每辆车写一个新的Module
对象。在完成解析之后,我想通过删除重复项并单独存储模块来优化数据库,因此车辆只会通过ID引用模块。
这就是问题出现的地方:我可以轻松地从每个Module
的{{1}} - 结构中获取所有CompatibleModules
,将它们存储在Vehicle
中从而检测碰撞。但是在我检测到碰撞之后,将HashSet
中所有副本的引用替换为原始副本并不是一项微不足道的任务。
在这种情况下,替换所有重复项引用的优雅方法是什么?
答案 0 :(得分:3)
不要将模块视为车辆的一部分,将它们视为用于制造车辆的独立部件。
因此,您希望拥有一个管理可用模块的工厂,并在您制造车辆时,向工厂询问必要的模块。然后工厂确保每个模块“类型”或“实例”在整个系统中只存在一次。
[编辑] 一种解决方案是将List<Engine> compatibleEngines
替换为Set<Engine> compatibleEngines = new LinkedHashSet<>();
。 LinkedHashSet
保留了插入顺序。完成此更改后,您只需添加模块即可相互覆盖。
注意:要使其正常工作,您必须覆盖equals()
和hashCode()
。
如果您不能这样做,那么创建一个包含良好equals()
和hashCode()
的包装器对象。要清理重复项:
Set<Wrapper> wrappedEngines = new LinkedHashSet<>();
for( Engine e : compatibleEngines ) {
wrappedEngines.add( new Wrapper( e ) );
}
compatibleEngines.clear();
for( Wrapper e : wrappedEngines ) {
compatibleEngines.add( e.getDelegate() );
}
答案 1 :(得分:0)
这是我丑陋的解决方案。我不喜欢它,但它完成了这项工作。尽管如此,这不是我的问题的答案,只是这个特定问题的解决方案......
void bruteForce(List<CompatibleModules> compatibles) {
for (CompatibleModules c : compatibles) {
c.defaultEngine = replaceDuplicate(c.defaultEngine);
replaceDuplicates(c.compatibleEngines);
// TODO: add all other fields of CompatibleModules here...
}
}
/** Mapping: Module ID -> Module */
protected Map<String, Module> moduleMap = new HashMap<String, Module>();
protected <M extends Module> M replaceDuplicate(M m) {
String id = m.getID();
Module stored = moduleMap.get(id);
if(stored != null) {
return (M) stored;
} else {
moduleMap.put(id, m);
return m;
}
}
protected <M extends Module> List<M> replaceDuplicates(List<M> modules) {
for (int i = 0; i < modules.size(); i++) {
M m = modules.get(i);
M r = replaceDuplicate(m);
if(r != m) {
modules.remove(i);
modules.add(i, r);
}
}
return modules;
}
我正在使用这个奇怪的<M extends Module>
- 模式使replaceDuplicates
接受所有Module
子类的列表,这只是解决Java泛型设计中的一个缺陷。