2

ジェネリックリスナーの通知束用に抽象ジェネリックプロバイダーを実装しました。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. 別の非 hashCode バッキング コレクションを使用します -- しかしWeakHashMap、弱い参照を自動的に管理するので、私にとってはとても便利です。

  2. 単純な実装の抽象クラスなど、非汎用リスナーを使用しますequals() { return (this == object); }が、これはそれほど柔軟ではありません

  3. addListener(E)単純な equals() を使用してリスナーにラッパーを使用します -- ただし、このラッパーは弱い参照のために呼び出し元に対して透過的ではありません

別のアイデア?

4

2 に答える 2

4

WeakHashMapちょっと壊れています。弱鍵を使用しますが、IDハッシュは使用しません。equals()キータイプのandが「identity」を使用しない限り、をhashCode()使用しないでくださいWeakHashMapWeakHashMap代わりに、との組み合わせである何かが必要ですIdentityHashMap

1つの可能性は、GoogleコレクションのMapMakerを使用することです。キーが弱いか弱い場合は、キーにIDハッシュ/等式を自動的に使用します。例えば:

ConcurrentMap<K, V> myMap = new MapMaker().weakKeys().makeMap();
于 2009-11-10T19:26:01.733 に答える
1

問題の核心は、リスナーの実装がサブクラス化されているが、 /AbstractListをオーバーライドしていないことです。このタイプの継承 (実装継承) はオブジェクト指向の原則 (ポリモーフィック代替可能性の原則) に違反するため、強くお勧めします。equals()hashCode()

AbstractListが必要な場合は を参照する可能性があり、独自のequals()との実装も提供するカスタム リスナー クラスを実装する方がはるかに優れていhashCode()ます。

于 2009-11-10T18:13:43.667 に答える