是否可以在Java中使用其他两个映射支持Map?

时间:2014-01-23 09:37:44

标签: java collections map

我的应用程序中有两张地图,让它成为'id by id'和'manager by id'。我使用它们来获取用户ID:

Map<Id, Person> usersById = new HashMap<Id, Person>();
Map<Id, Person> managersById = new HashMap<Id, Person>();
Person me = usersById.get(myId);

这两个实体都是人,所以有时我需要通过其ID找到一个任意人。是的,我可以在一张地图中搜索,然后在另一张地图中搜索:

Person findArbitraryPerson(Id id) {
    Person candidate = usersById.get(myId);
    if (candidate == null) {
      candidate = managersById.get(myId);
    }
    return candidate;
}

但是,可能有更好的方法吗? 是的,我可以创建一个公共人员地图。但是我每次到达时都要向该地图添加一个新的Person实例,并将其删除等。是否有可能创建一种“由两个地图支持”的地图,以自动更新内容?正如我可以在集合框架中创建由原始地图支持的子地图。

或者,可能有更好的解决方案吗?

3 个答案:

答案 0 :(得分:3)

我的comment和@ BrianRoach comment的扩展(和/或结论):

public abstract class Person {
   // general members and methods shared by managers and users
}

public class User extends Person {
    // User specific members and methods
}

public class Manager extends Person {
   // Manager specific members and methods
}

Map<Id,Person> map = new HashMap<Id, Person>();
map.put(new Id(), new Manager());
map.put(new Id(), new User());

OR(如果你是如此倾向),只需在Person对象上有一个布尔成员:isManager并使用适当的getter / setter。

答案 1 :(得分:1)

这是一个只读地图(未经测试!),由任意数量的其他地图备份:

 private class ReadonlyProxyMap<K, V> implements Map<K, V> {

        private final List<Map<K, V>> maps = new ArrayList<>();

        public void addMap(Map<K, V> map) {
            maps.add(map);
        }

        @Override
        public int size() {
            return entrySet().size();
        }

        @Override
        public boolean isEmpty() {
            for (Map<K, V> map : maps) {
                if (!map.isEmpty()) {
                    return false;
                }
            }
            return true;
        }

        @Override
        public boolean containsKey(Object key) {
            for (Map<K, V> map : maps) {
                if (map.containsKey(key)) {
                    return true;
                }
            }
            return false;
        }

        @Override
        public boolean containsValue(Object value) {
            for (Map<K, V> map : maps) {
                if (map.containsValue(value)) {
                    return true;
                }
            }
            return false;
        }

        @Override
        public V get(Object key) {
            for (Map<K, V> map : maps) {
                if (map.containsKey(key)) {
                    return map.get(key);
                }
            }
            return null;
        }

        @Override
        public V put(K key, V value) {
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        }

        @Override
        public V remove(Object key) {
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        }

        @Override
        public void putAll(Map<? extends K, ? extends V> m) {
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        }

        @Override
        public void clear() {
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        }

        @Override
        public Set<K> keySet() {
            Set<K> keySet = new HashSet<>();
            for (Map<K, V> map : maps) {
                keySet.addAll(map.keySet());
            }
            return keySet;
        }

        @Override
        public Collection<V> values() {
            List<V> values = new ArrayList<>();
            for (Map.Entry<K, V> entry : entrySet()) {
                values.add(entry.getValue());
            }
            return values;
        }

        @Override
        public Set<Map.Entry<K, V>> entrySet() {
            Set<K> keySet = new HashSet<>();
            Set<Map.Entry<K, V>> entrySet = new HashSet<>();
            for (Map<K, V> map : maps) {
                for (Map.Entry<K, V> entry : map.entrySet()) {
                    if (!keySet.contains(entry.getKey())) {
                        entrySet.add(entry);
                        keySet.add(entry.getKey());
                    }
                }
            }
            return entrySet;
        }

    }

然后你可以使用:

Map<Id, Person> usersById = new HashMap<>();
Map<Id, Person> managersById = new HashMap<>();
ReadonlyProxyMap<Id, Person> allPersons = new ReadonlyProxyMap<>();

...

allPersons.addMap(usersById);
allPersons.addMap(managersById);

...

Person findArbitraryPerson(Id id) {
    return allPersons.get(myId);
}

答案 2 :(得分:0)

当然经理人也是人?更好的方法是制作Person s的地图,并Manager展开Person

让某人查询地图并返回找到的Person。让管理器查询映射并检查返回的对象是否为Manager的实例,如果不是则返回null。

我会将整个HashMap包装到您自己的类中,该类应该使用适当的调用/检查来实现getPerson()getManager()getUser()。这也将API与实现分离,因此将来您可以随时更改它,而不必更改任何其他代码。