Java: реализация поставщика уведомлений против карты, управляемой хешкодом

StackOverflow https://stackoverflow.com/questions/1709965

Вопрос

Я внедрил абстрактного общего провайдера для уведомлений Грубка общих слушателей 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

Какое решение лучше всего?

  1. Используйте еще одну коллекцию, не являющуюся резервным кодом-но WeakHashMap для меня так мило, потому что автоматически управлять слабыми ссылками для меня

  2. Используйте негенерический слушатель, например, абстрактный класс с простым equals() { return (this == object); } реализация - но это не так гибко

  3. Используйте некоторую обертку для слушателей с простым равным () - но эта обертка не может быть прозрачной для addListener(E) звонящий из -за слабых ссылок

Другие идеи?

Это было полезно?

Решение

WeakHashMap как бы сломан. Он использует слабые ключи, но он не использует хэширование идентификации. Если equals() а также hashCode() вашего типа ключа Использование "Identity", вы не должны использовать WeakHashMap. Анкет Вместо этого вам нужно что -то, что сочетает WeakHashMap а также IdentityHashMap.

Одна возможность - использовать Картофмейнер из коллекций Google. Он автоматически использует идентификационные хэши/равенство для клавиш, если клавиши слабые или мягкие. например:

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

Другие советы

Суть проблемы, по -видимому, заключается в том, что реализация вашего слушателя является подклассом AbstractList, но не переопределяется equals() / hashCode(). Анкет Я настоятельно рекомендую против этого типа наследования (наследование реализации), поскольку оно нарушает уоооплаты (принцип полиморфной замещаемости).

Было бы гораздо лучше внедрить пользовательский класс слушателей, который, возможно, ссылается на AbstractList Если это требует одного, и это также обеспечивает свой собственный equals() а также hashCode() реализации.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top