جافا: تنفيذ مزود الإعلام مقابل الخريطة التي يقودها Hashcode

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. استخدام مجموعة دعم أخرى غير hashcode - ولكن WeakHashMap حلوة جدا بالنسبة لي، لأنه يدير تلقائيا المراجع الضعيفة بالنسبة لي

  2. استخدم المستمع غير العام، على سبيل المثال فئة مجردة مع بسيطة equals() { return (this == object); } التنفيذ - ولكن هذا ليس مرن جدا

  3. استخدم بعض المجمع للمستمعين مع يساوي بسيط () - ولكن هذا الغلاف لا يمكن أن يكون شفافا addListener(E) المتصل بسبب المراجع الضعيفة

أفكار أخرى؟

هل كانت مفيدة؟

المحلول

WeakHashMap هو نوع من كسر. يستخدم مفاتيح ضعيفة، لكنه لا يستخدم التجزئة الهوية. ما لم يكن equals() و hashCode() من نوع المفتاح الخاص بك استخدام "الهوية"، يجب أن لا تستخدم WeakHashMap. وبعد بدلا من ذلك، تحتاج إلى شيء مزيج من WeakHashMap و IdentityHashMap.

احتمال واحد هو استخدام mapmaker. من مجموعات جوجل. يستخدم تلقائيا اجل / مساواة الهوية للمفاتيح إذا كانت المفاتيح ضعيفة أو لينة. على سبيل المثال:

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

نصائح أخرى

يبدو أن جوهر المشكلة هو أن تنفيذ المستمع الخاص بك هو الفئة الفرعية AbstractList, ، ولكن ليس تجاوز equals() / hashCode(). وبعد أود أن أوصى بشدة ضد هذا النوع من الميراث (ميراث التنفيذ) لأنه ينتهك مبادئ OO (مبدأ الاستبدال متعدد الجنس).

سيكون من الأفضل بكثير تنفيذ فئة مستمع مخصصة والتي ربما تشير إلى AbstractList إذا كانت تتطلب واحدة، وهذا يوفر أيضا خاصة به equals() و hashCode() تطبيقات.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top