Java: la mise en œuvre du fournisseur de notification par rapport à la carte axée sur hashCode-
-
19-09-2019 - |
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?
-
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 -
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 -
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?
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()
.