質問

一般的なリスナーの通知のために抽象的なジェネリックプロバイダーを実装しました 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 リスナーインスタンスは1つだけを受け入れます!それは明らかです - 方法 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. 単純なequal()を持つリスナーにラッパーを使用しますが、このラッパーはに透過的ではありません addListener(E) 参照が弱いため発信者

別のアイデア?

役に立ちましたか?

解決

WeakHashMap ちょっと壊れています。弱いキーを使用しますが、アイデンティティハッシュは使用しません。でない限り equals()hashCode() キータイプの「アイデンティティ」を使用すると、使用すべきではありません WeakHashMap. 。代わりに、の組み合わせであるものが必要です WeakHashMapIdentityHashMap.

1つの可能性は使用することです マップメーカー Googleコレクションから。キーが弱いか柔らかい場合、キーのアイデンティティハッシュ/等式を自動的に使用します。例えば:

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

他のヒント

問題の核心は、リスナーの実装がサブクラス化しているようです AbstractList, 、しかし、オーバーライドしていません equals() / hashCode(). 。このタイプの継承(実装継承)に対して強くお勧めします。これは、OO原理(多型代替性の原理)に違反しているためです。

おそらく参照するカスタムリスナークラスを実装する方がはるかに良いでしょう AbstractList それが必要な場合、それはそれ自身も提供します equals()hashCode() 実装。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top