简体   繁体   English

Java中是否可以有另外两个地图作为后盾?

[英]Is it possible to have a Map backed by two other maps in Java?

I have two maps in my application, let it be 'users by id' and 'managers by id'. 我的应用程序中有两张地图,分别是“ ids用户”和“ manager by id”。 I use them to get user by its id: 我用它们通过ID来获取用户:

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

Both the entities are persons, so sometime I need to find an arbitrary person by its id. 两个实体都是人,因此有时我需要通过其ID查找任意人。 Yes, I can search in one map and then in another one: 是的,我可以在一张地图中搜索,然后在另一张地图中搜索:

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

But, may be, there is a better approach? 但是,也许有更好的方法? Yes, I can create a common map of persons. 是的,我可以创建一个通用的人员地图。 But I would have to add a new Person instance to that map each time it arrives, and remove it etc. Is it possible to create a kind of a 'backed by two maps' map, to renew it contents automatically? 但是我每次到达该地图时都必须为其添加一个新的Person实例,然后将其删除等。是否可以创建一种“由两张地图支持”的地图,以自动更新其内容? Just as I can create a subMap backed by original map in Collections framework. 就像我可以在Collections框架中创建由原始地图支持的subMap一样。

Or, may be, there is a better solution? 或者,也许有更好的解决方案?

An extension (and/or conclusion) to my comment and @BrianRoach's comment : 我的评论和@BrianRoach的评论的扩展(和/或结论):

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 (if you were so inclined), just have a boolean member on the Person object: isManager with appropriate getter/setter. 或(如果您很喜欢),则在Person对象上只有一个布尔成员: isManager和适当的getter / setter。

Here is a readonly Map (untested !), which is backed up by any number of other Maps: 这是一个只读的Map(未经测试的!),由任意数量的其他Map备份:

 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;
        }

    }

Then you can use: 然后,您可以使用:

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);
}

Surely managers are also people? 当然经理人也是人吗? The better way to do this is to have a map of Person s and have Manager extend Person . 做到这一点的更好方法是拥有一个Person的映射,并让Manager扩展Person

To get a person query the map and return the found Person . 要获得人员查询地图并返回找到的Person To get a manager query the map and check if the returned object is an instanceof Manager and return null if it is not. 要获取经理,请查询地图并检查返回的对象是否为Manager的instance,如果不是,则返回null。

I would wrap the whole HashMap into a class of your own and that class should implement getPerson() , getManager() , getUser() with appropriate calls/checks. 我会将整个HashMap包装到您自己的类中,该类应通过适当的调用/检查实现getPerson()getManager()getUser() This also decouples the API from the implementation so in future you can always change it and not have to change any other code. 这也使API与实现脱钩,因此将来您可以随时更改它,而不必更改任何其他代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM