Question

Je l'ai mis en œuvre abstraite fournisseur générique pour groupe de notification de E générique des auditeurs, descendants doivent passer outre notifyListener(E) avec le code de notification spécifique. Pour une liste de soutien des auditeurs je choisis WeakHashMap<K,V>. Les auditeurs doivent avoir lieu comme références faibles:

abstract public class NotificationProvider<E> {

    private Map<E, Object> listeners = new WeakHashMap<E, Object>();

    public addListener(E listener) {
        listeners.put(listener, null);
    }

    public void notifyListeners() {
        for (E listener: listeners.keySet())
            notifyListener(listener);
    }

    abstract protected void notifyListener(E listener);
}

Utilisation typique:

    NotificationProvider<MyListener> provider;
    provider = new NotificationProvider<MyListener>() {
        @Override
        protected void notifyListener(MyListener listener) {
            listener.myNotification();
        }
    }
    provider.addListener(myListener1);
    provider.addListener(myListener2);
    provider.notifyListeners();

Tout fonctionne bien, mais quand j'ai besoin AbstractList classe descendante comme auditeur, la sauvegarde WeakHashMap accepte une seule instance d'écoute! Il est clair -. Méthodes hashCode() et equals() sur les auditeurs reviennent même valeur pour tous les cas (listes vides), de sorte que WeakHashMap.put remplacer écouteur précédemment ajouté

    public class MyList extends AbstractList<MyItem> {
        // some implementation
    }
    NotificationProvider<MyList> provider;
    provider = new NotificationProvider<MyList>() {
        @Override
        protected void notifyListener(MyList listener) {
            // some implementation
        }
    }
    MyList list1 = new MyList();
    MyList list2 = new MyList();
    provider.addListener(list1);
    provider.addListener(list2); 
    provider.notifyListeners();  // only list2 instance is notified

Quelle est la meilleure solution?

  1. utiliser une autre collection de support non hashCode - mais WeakHashMap est si doux pour moi, parce que la gestion automatique des références faibles pour moi

  2. utiliser auditeur non générique, par exemple classe abstraite avec implémentation simple de equals() { return (this == object); } - mais ce n'est pas si flexible

  3. utiliser un emballage pour les auditeurs avec de simples égaux () - mais cette enveloppe ne peut pas être transparente pour addListener(E) appelant en raison de références faibles

Une autre des idées?

Était-ce utile?

La solution

WeakHashMap est une sorte de cassé. Il utilise des clés faibles, mais il n'utilise pas le hachage d'identité. À moins que le equals() et hashCode() de votre utilisation de type clé « identité », vous ne devriez pas utiliser WeakHashMap. Au lieu de cela vous avez besoin quelque chose qui est une combinaison de WeakHashMap et IdentityHashMap.

Une possibilité est d'utiliser Google Map Maker de collections. Il utilise automatiquement hash d'identité / égalité des clés si les touches sont faibles ou mous. par exemple:

ConcurrentMap<K, V> myMap = new MapMaker().weakKeys().makeMap();

Autres conseils

Le nœud du problème semble être que votre mise en œuvre de l'auditeur est le sous-classement AbstractList, mais pas primordial equals() / hashCode(). Je recommande fortement contre ce type d'héritage (l'héritage de mise en œuvre) car elle viole les principes OO-(principe de substituabilité polymorphes).

Il serait bien préférable de mettre en œuvre une classe d'écoute personnalisée qui fait référence peut-être un AbstractList si elle a besoin d'un, et qui fournit également ses propres implémentations de equals() et hashCode().

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top