替换重复的java对象,包括所有引用

时间:2014-01-31 13:42:53

标签: java object reference

我知道我们已经对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中所有副本的引用替换为原始副本并不是一项微不足道的任务。

在这种情况下,替换所有重复项引用的优雅方法是什么?

2 个答案:

答案 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泛型设计中的一个缺陷。