Java: реализация поставщика уведомлений против карты, управляемой хешкодом
-
19-09-2019 - |
Вопрос
Я внедрил абстрактного общего провайдера для уведомлений Грубка общих слушателей E
, потомки должны отменять notifyListener(E)
с конкретным кодом уведомления. Для списка слушателей я выбираю WeakHashMap<K,V>
. Анкет Слушатели должны содержаться как слабые ссылки:
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);
}
Типичное использование:
NotificationProvider<MyListener> provider;
provider = new NotificationProvider<MyListener>() {
@Override
protected void notifyListener(MyListener listener) {
listener.myNotification();
}
}
provider.addListener(myListener1);
provider.addListener(myListener2);
provider.notifyListeners();
Все работает хорошо, но когда мне нужно AbstractList
Потомки класса в качестве слушателя, поддержка WeakHashMap
принимает только один экземпляр слушателя! Это ясно - методы hashCode()
а также equals()
При слушателях возвращает одно значение для всех экземпляров (пустые списки), поэтому WeakHashMap.put
только замените ранее добавленный слушатель.
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
Какое решение лучше всего?
Используйте еще одну коллекцию, не являющуюся резервным кодом-но
WeakHashMap
для меня так мило, потому что автоматически управлять слабыми ссылками для меняИспользуйте негенерический слушатель, например, абстрактный класс с простым
equals() { return (this == object); }
реализация - но это не так гибкоИспользуйте некоторую обертку для слушателей с простым равным () - но эта обертка не может быть прозрачной для
addListener(E)
звонящий из -за слабых ссылок
Другие идеи?
Решение
WeakHashMap
как бы сломан. Он использует слабые ключи, но он не использует хэширование идентификации. Если equals()
а также hashCode()
вашего типа ключа Использование "Identity", вы не должны использовать WeakHashMap
. Анкет Вместо этого вам нужно что -то, что сочетает WeakHashMap
а также IdentityHashMap
.
Одна возможность - использовать Картофмейнер из коллекций Google. Он автоматически использует идентификационные хэши/равенство для клавиш, если клавиши слабые или мягкие. например:
ConcurrentMap<K, V> myMap = new MapMaker().weakKeys().makeMap();
Другие советы
Суть проблемы, по -видимому, заключается в том, что реализация вашего слушателя является подклассом AbstractList
, но не переопределяется equals()
/ hashCode()
. Анкет Я настоятельно рекомендую против этого типа наследования (наследование реализации), поскольку оно нарушает уоооплаты (принцип полиморфной замещаемости).
Было бы гораздо лучше внедрить пользовательский класс слушателей, который, возможно, ссылается на AbstractList
Если это требует одного, и это также обеспечивает свой собственный equals()
а также hashCode()
реализации.