[英]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.