У меня есть два класса, ClassA
и ClassB
, а также "многие многим" AssociationClass
. Я хочу структуру, которая содержит ассоциации между A и B так, чтобы я мог найти дубликат для каждого экземпляра A или B.
Я думал об использовании Hashmap с парными ключами:
Hasmap<Pair<ClassA, ClassB>, AssociationClass> associations;
Таким образом, я могу добавить и удалить ассоциацию между двумя экземплярами ClassA
и ClassB
, и я могу запросить отношение для двух приведенных примеров.
Однако я пропускаю функцию получения всех ассоциаций, определенных для приведенного примера ClassA
или ClassB
.
Я мог сделать это грубой силой и цикл по всем ключам карты для поиска ассоциаций между приведенным примером, но это неэффективно и не изящно.
Вы знаете о какой-либо структуре данных / свободная библиотека, которая включает это? Я не хочу изобретать велосипед.
NB: Это не вопрос "о базе данных". Этими объектами является чистый POJO, используемый для живого вычисления, мне не нужен материал персистентности.
Спасибо за ваши предложения.
Наконец-то я заново изобрел колесо ... Я написал общий класс для хранения ассоциаций. Я использую две синхронизированные карты карт.
Держатель ассоциаций предоставляет следующие методы
void setAssociation(LeftClass left, RightClass right, AssociationClass assoc);
AssociationClass getAssociation(LeftClass left, RightClass right);
Map<RightClass, AssociationClass> getAssocationsLeft(LeftClass left);
Map<LeftClass, AssociationClass> getAssocationsRight(RightClass right);
void removeAssociation(LeftClass left, RightClass right);
Вот код:
import java.util.HashMap;
/** This class holds many to many associations between two classes. */
public class AssociationHolder<LeftClass, RightClass, AssociationClass> {
// -------------------------------------------------------
// Attributes
// -------------------------------------------------------
private HashMap<LeftClass, HashMap<RightClass, AssociationClass>> associationsLeft =
new HashMap<LeftClass, HashMap<RightClass,AssociationClass>>();
private HashMap<RightClass, HashMap<LeftClass, AssociationClass>> associationsRight =
new HashMap<RightClass, HashMap<LeftClass,AssociationClass>>();
// -------------------------------------------------------
// Methods
// -------------------------------------------------------
/**
* Set an association between two instance.
* Any prior association is overwritten.
*/
public void setAssociation(LeftClass left, RightClass right, AssociationClass association) {
// Get the map for the left
HashMap<RightClass, AssociationClass> leftMap = this.associationsLeft.get(left);
// No association defined yet for this left key ? => Create new map
if (leftMap == null) {
leftMap = new HashMap<RightClass, AssociationClass>();
this.associationsLeft.put(left, leftMap);
}
// Get the map for the right
HashMap<LeftClass, AssociationClass> rightMap = this.associationsRight.get(right);
// No association defined yet for this right key ? => Create new map
if (rightMap == null) {
rightMap = new HashMap<LeftClass, AssociationClass>();
this.associationsRight.put(right, rightMap);
}
// Set the assoication on both maps
leftMap.put(right, association);
rightMap.put(left, association);
}
/** @return null if no association found. */
public AssociationClass getAssociation(LeftClass left, RightClass right) {
// Use left maps (could have used the right one as well)
HashMap<RightClass, AssociationClass> leftMap = this.associationsLeft.get(left);
if (leftMap == null) return null;
return leftMap.get(right);
}
/** Get all associations defined for a given Left instance. */
public HashMap<RightClass, AssociationClass> getAssociationsLeft(LeftClass left) {
HashMap<RightClass, AssociationClass> leftMap = this.associationsLeft.get(left);
// No map defined ? return empty one instead of null
if (leftMap == null) {
return new HashMap<RightClass, AssociationClass>();
} else {
return leftMap;
}
}
/** Get all associations defined for a given Right instance. */
public HashMap<LeftClass, AssociationClass> getAssociationsRight(RightClass right) {
HashMap<LeftClass, AssociationClass> rightMap = this.associationsRight.get(right);
// No map defined ? return empty one instead of null
if (rightMap == null) {
return new HashMap<LeftClass, AssociationClass>();
} else {
return rightMap;
}
}
/**
* Remove an association between two instances.
*/
public void removeAssociation(LeftClass left, RightClass right) {
HashMap<RightClass, AssociationClass> leftMap = this.getAssociationsLeft(left);
HashMap<LeftClass, AssociationClass> rightMap = this.getAssociationsRight(right);
leftMap.remove(right);
rightMap.remove(left);
}
}
Я надеюсь, что это поможет кому-то в будущем.
Используя свой AssociationClass, вы можете просто, чтобы ClassA и ClassB оба содержали ссылку на AssociationClass:
private AssociationClass association;
Или другой метод ...
ClassA может содержать:
private List<ClassB> classBList;
и ClassB могут содержать:
private List<ClassA> classAList;
Реализуя это, вы можете получить доступ к своим ассоциациям изнутри связанного класса.
Может быть, Multimap или BiMap из библиотеки коллекций Google могут сделать то, что вам нужно.
Это похоже на проблему, в которой у вас есть данные, которые вы хотите получить с помощью нескольких ключей. Вы хотите искать по ClassA, а также по ClassB. Обычно это приводит к нескольким картам поверх данных, так что каждая карта хранит ключ поиска в базовых данных. Возможно, что-то вроде этого сработает:
public class Data {
public ClassA a;
public ClassB b;
public AssociationClass association;
}
Map<ClassA, Data> aData;
Map<ClassB, Data> bData;
Map<AssociationClass, Data> associationData;
Вставка происходит следующим образом:
Data data = new Data()
aData.put(data.a, data);
bData.put(data.b, data);
associationData.put(data.association, data);
Получая данные, вы можете запросить каждую из карт, чтобы получить то, что вы хотите. Вы даже можете использовать свой класс Pair
в качестве другого индекса в данных:
Map<Pair<ClassA, ClassB>, Data> pairData;
Проблема с этим подходом состоит в том, что если базовые данные сильно меняются, вы должны убедиться, что все карты синхронизированы. Если это в основном проблема только для чтения, вы создаете карты, а затем просто запрашиваете карту с вашим ключом в данных.
Почему бы не поместить карту в каждый класс?
class ClassA {
...
private Map<ClassB, AssociationClass> associations
= HashMap<ClassB, AssociationClass>();
...
}
class ClassA {
...
private Map<ClassA, AssociationClass> associations
= HashMap<ClassB, AssociationClass>();
...
}
Рмаримон прав в том, что для этого требуются две карты, но я думаю, вам нужны A-B, а не A-данные и B-данные.
Итак, вам просто нужны две карты:
Hashmap bByA = new HashMap();
Hashmap aByB = new HashMap();
Это дает вам все, что вы, кажется, хотите, бесплатно и легко.