2008-10-04 10 views
1

Je cherchais un moyen générique pour gérer les associations bidirectionnelles et un moyen de gérer les mises à jour inverses dans le code Java écrit manuellement.Java Framework générique pour gérer les associations bidirectionnelles et les mises à jour inverses

Pour ceux qui ne savent pas de quoi je parle, voici un exemple. Ci-dessous sont mes résultats actuels de solutions (insatisfaisantes).

public class A { 
    public B getB(); 
    public void setB(B b); 
} 

public class B { 
    public List<A> getAs(); 
} 

Maintenant, quand la mise à jour toute fin de l'association, afin de maintenir la cohérence, l'autre extrémité doit être mis à jour. Soit manuellement à chaque fois

a.setB(b); 
b.getA().add(a); 

ou en mettant le code correspondant dans le setter/getter et utiliser une implémentation de liste personnalisée.

J'ai trouvé un projet périmé, non maintenu dont les dépendances ne sont plus disponibles (https://e-nspire-gemini.dev.java.net/). Il traite le problème en utilisant des annotations qui sont utilisées pour injecter le code nécessaire automatiquement.

Est-ce que quelqu'un connaît un autre cadre qui traite de manière générique et discrète ala gemini?

ciao, Elmar

Répondre

5

collections google (à partir du code interne de google) - http://code.google.com/p/google-collections/ Java est Generics compatible (non seulement compatible, utilise génériques très bien)

classe BiMap - http://google-collections.googlecode.com/svn/trunk/javadoc/index.html?http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/package-summary.html permet de Bidirectionnelle les associations.

Certaines de ces classes devraient faire leur chemin dans 7.

JDK
0

A moins abstraite les setters, vous allez devoir fournir une sorte de mécanisme de notification d'événements. Si vos objets sont JavaBeans, vous envisagez d'utiliser PropertyChangeSupport et de déclencher des événements de changement de propriété.

Si vous faites cela (ou avez un autre mécanisme pour détecter les changements), alors Glazed Lists fournit un ObservableElementList qui pourrait facilement être utilisé pour gérer la synchronisation d'association de la fin de la liste (par exemple ajouter A à List < A> a.setB (b)). L'autre direction est facilement manipulée en utilisant la surveillance des changements de propriété (ou équivalent). Je me rends compte que ce n'est pas une solution générique, mais il semble que ce serait une base facile pour l'un.

Notez que quelque chose comme cela besoin une liste spéciale mise en œuvre dans la classe B - aucun moyen à court de solutions de type AOP que vous pouvez le manipuler dans le cas général (à savoir en utilisant ArrayList ou quelque chose comme ça).

Je devrais également souligner que ce que vous essayez d'accomplir est quelque chose du Saint-Graal de la liaison de données. Il existe quelques implémentations décentes pour la liaison au niveau du terrain (des choses comme les getters et les setters) (voir JGoodies binding et JSR 295 pour des exemples). Il y a aussi une implémentation vraiment bonne pour la liaison de type liste (Glazed Lists, mentionnée ci-dessus). Nous utilisons les deux techniques de concert dans presque toutes nos applications, mais nous n'avons jamais essayé d'aller aussi abstrait que ce que vous demandez.

Si je concevais cela, je regardais quelque chose comme ceci:

AssociationBuilder.createAssociation(A a, Connector< A> ca, B b, Connector< B> cb, Synchronizer< A,B> sync) 

Connector est une interface qui permet une interface unique pour différents types de notification de changement. Synchronizer est une interface appelée pour s'assurer que les deux objets sont synchronisés chaque fois que l'un d'entre eux est modifié. ChangeInfo fournit des données sur quel membre a changé, et quelles étaient les modifications en réalité. Nous sommes. Si vous essayez vraiment de garder ce générique, alors vous avez à peu près mettre l'implémentation de ce à l'utilisateur du cadre.

Avec ce qui précède, il serait possible d'avoir un certain nombre de connecteurs et de synchroniseurs prédéfinis répondant à différents critères de liaison.

Fait intéressant, la signature de méthode ci-dessus est assez similaire à l'appel de méthode JSR 295 createAutoBinding(). Les objets de propriété sont l'équivalent de Connector. JSR 295 n'a pas le Synchronizer (à la place, ils ont une stratégie de liaison spécifiée comme ENUM - plus JSR 295 fonctionne uniquement avec property-> property binding, essayant de lier une valeur de champ d'un objet à l'appartenance de la liste dans un autre objet n'est même pas sur la table pour eux).

0

Pour donner un sens, ces calsses seront des pairs. Je suggère un mécanisme paquet-privé (en l'absence d'un ami) pour garder la cohérence.

public final class A { 
    private B b; 
    public B getB() { 
     return b; 
    } 
    public void setB(final B b) { 
     if (b == this.b) { 
      // Important!! 
      return; 
     } 
     // Be a member of both Bs (hence check in getAs). 
     if (b != null) { 
      b.addA(this); 
     } 
     // Atomic commit to change. 
     this.b = b; 
     // Remove from old B. 
     if (this.b != null) { 
      this.b.removeA(this); 
     } 
    } 
} 

public final class B { 
    private final List<A> as; 
    /* pp */ void addA(A a) { 
     if (a == null) { 
      throw new NullPointerException(); 
     } 
     // LinkedHashSet may be better under more demanding usage patterns. 
     if (!as.contains(a)) { 
      as.add(a); 
     } 
    } 
    /* pp */ void removeA(A a) { 
     if (a == null) { 
      throw new NullPointerException(); 
     } 
     as.removeA(a); 
    } 
    public List<A> getAs() { 
     // Copy only those that really are associated with us. 
     List<A> copy = new ArrayList<A>(as.size()); 
     for (A a : as) { 
      if (a.getB() == this) { 
       copy.add(a); 
      } 
     } 
     return Collection.unmodifiableList(copy); 
    } 
} 

(Disclaime. Non testé ou même compilé)

La plupart du temps sauf en toute sécurité (peut fuir en cas d'exception). La sécurité du fil, beaucoup, la performance, la bibliothèque, etc., est laissée comme un exercice au lecteur intéressé.

+0

Merci pour la réponse, mais je cherchais une solution qui traite de ceci d'une manière générique, sans code-instructif. –

0

Merci pour toutes les suggestions. Mais aucun n'est venu près de ce que je cherchais, j'ai probablement formulé la question d'une mauvaise façon.

Je cherchais un remplacement pour les gemini, donc pour un moyen de gérer cela de manière discrète, sans polluer le code avec des vérifications sans fin et des implémentations de listes spéciales. Ceci appelle naturellement une approche basée sur AOP, comme suggéré par Kevin. Quand j'ai regardé un peu plus loin, j'ai trouvé un paquet de gemini sur cnet qui contient toutes les sources et dépendances avec les sources. Les sources manquantes pour les dépendances étaient la seule préoccupation qui m'empêchait de l'utiliser. Depuis maintenant toutes les sources sont disponibles, les bugs peuvent être corrigés. Dans le cas où quelqu'un cherche ceci: http://www.download.com/Gemini/3000-2413_4-10440077.html

Questions connexes