Подтвердить что ты не робот

Java для многих ассоциаций

У меня есть два класса, ClassA и ClassB, а также AssociationClass "многие ко многим". Мне нужна структура, которая содержит связи между A и B, чтобы я мог найти аналог для каждого экземпляра A или B.

Я подумал об использовании Hashmap с парой ключей:

Hasmap<Pair<ClassA, ClassB>, AssociationClass> associations;

Таким образом, я могу добавить и удалить связь между двумя экземплярами ClassA и ClassB, и я могу запросить отношение для двух данных экземпляров.

Однако я ClassA возможность получения всех ассоциаций, определенных для данного экземпляра ClassA или ClassB.

Я мог бы сделать это с помощью грубой силы и перебрать все ключи карты для поиска ассоциаций между данным экземпляром, но это неэффективно и не элегантно.

Знаете ли вы какую-либо структуру данных/бесплатную библиотеку, которая позволяет это? Я не хочу изобретать велосипед.

NB: Это не вопрос базы данных. Эти объекты - чистый POJO, используемый для живых вычислений, мне не нужны постоянные вещи.

4b9b3361

Ответ 1

Спасибо за ваши предложения.

Я наконец заново изобрел колесо... Я написал общий класс для проведения ассоциаций. Я использую две карты карт, синхронизированные.

Держатель ассоциаций предоставляет следующие методы

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

Я надеюсь, что это может помочь кому-то в будущем.

Ответ 2

Здесь моя реализация, основанная на guava Multimap:

public class ImmutableBiMultimap<K, V> {
    private final ImmutableSetMultimap<K, V> kToV;
    private final ImmutableSetMultimap<V, K> vToK;

    public ImmutableBiMultimap (SetMultimap<K, V> keyToValueMap) {
        kToV = ImmutableSetMultimap.copyOf(keyToValueMap);

        SetMultimap<V, K> valueToKeyMap = HashMultimap.create();
        for (Entry<K, V> entry : kToV.entries()) {
            valueToKeyMap.put(entry.getValue(), entry.getKey());
        }

        vToK = ImmutableSetMultimap.copyOf(valueToKeyMap);
    }

    public ImmutableSet<V> getValuesForKey(K key) {
        return kToV.get(key);
    }

    public ImmutableSet<K> getKeysForValue(V value) {
        return vToK.get(value);
    }
}

Ответ 4

Это похоже на проблему, в которой у вас есть данные, которые вы хотите получить с помощью нескольких ключей. Вы хотите выполнить поиск по 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;

Проблема с этим подходом заключается в том, что если базовые данные сильно изменяются, вы должны убедиться, что все карты синхронизированы. Если это в основном проблема с чтением, тогда вы создаете карты, а затем просто запрашиваете один с вашим ключом в данные.

Ответ 5

Используя ваш ClassClass, вы можете просто иметь ClassA и ClassB, содержащие ссылку на AssociationClass:

private AssociationClass association;

Или другой метод...

ClassA может содержать:

private List<ClassB> classBList;

и ClassB могут содержать:

private List<ClassA> classAList;

Внедряя это, вы можете получить доступ к своим ассоциациям из связанного класса.

Ответ 6

rmarimon прав, что ему нужны две карты, но я думаю, вы хотите A-B, а не A-данные и B-данные.

Итак, вам просто нужны две карты:


    Hashmap bByA = new HashMap();
    Hashmap aByB = new HashMap();

Это дает вам все, что вам кажется, свободным и легким.

Ответ 7

Почему бы не поместить карту в каждый класс?

class ClassA {
    ...
    private Map<ClassB, AssociationClass> associations
            = HashMap<ClassB, AssociationClass>();
    ...
}

class ClassA {
    ...
    private Map<ClassA, AssociationClass> associations
            = HashMap<ClassB, AssociationClass>();
    ...
}