جافا: تنفيذ مزود الإعلام مقابل الخريطة التي يقودها Hashcode
-
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
ما هو الحل الأمثل؟
استخدام مجموعة دعم أخرى غير hashcode - ولكن
WeakHashMap
حلوة جدا بالنسبة لي، لأنه يدير تلقائيا المراجع الضعيفة بالنسبة لياستخدم المستمع غير العام، على سبيل المثال فئة مجردة مع بسيطة
equals() { return (this == object); }
التنفيذ - ولكن هذا ليس مرن جدااستخدم بعض المجمع للمستمعين مع يساوي بسيط () - ولكن هذا الغلاف لا يمكن أن يكون شفافا
addListener(E)
المتصل بسبب المراجع الضعيفة
أفكار أخرى؟
المحلول
WeakHashMap
هو نوع من كسر. يستخدم مفاتيح ضعيفة، لكنه لا يستخدم التجزئة الهوية. ما لم يكن equals()
و hashCode()
من نوع المفتاح الخاص بك استخدام "الهوية"، يجب أن لا تستخدم WeakHashMap
. وبعد بدلا من ذلك، تحتاج إلى شيء مزيج من WeakHashMap
و IdentityHashMap
.
احتمال واحد هو استخدام mapmaker. من مجموعات جوجل. يستخدم تلقائيا اجل / مساواة الهوية للمفاتيح إذا كانت المفاتيح ضعيفة أو لينة. على سبيل المثال:
ConcurrentMap<K, V> myMap = new MapMaker().weakKeys().makeMap();
نصائح أخرى
يبدو أن جوهر المشكلة هو أن تنفيذ المستمع الخاص بك هو الفئة الفرعية AbstractList
, ، ولكن ليس تجاوز equals()
/ hashCode()
. وبعد أود أن أوصى بشدة ضد هذا النوع من الميراث (ميراث التنفيذ) لأنه ينتهك مبادئ OO (مبدأ الاستبدال متعدد الجنس).
سيكون من الأفضل بكثير تنفيذ فئة مستمع مخصصة والتي ربما تشير إلى AbstractList
إذا كانت تتطلب واحدة، وهذا يوفر أيضا خاصة به equals()
و hashCode()
تطبيقات.