2010-05-30 3 views
11

Почему списки слушателей (например, в Java те, которые используют addXxxListener() и removeXxxListener() для регистрации и отмены регистрации слушателей), называются списками и обычно реализованы как Lists? Будет не Set быть лучше подходит, так как в случае слушателей естьПочему списки списков слушателей?

  • Независимо от того, в каком порядке они дозвонились (хотя вполне могут быть такие потребности, но они особых случаев, обычные механизмы слушателем не дают таких гарантий), и
  • нет необходимости зарегистрировать один слушатель более одного раза (будь то делать, что должно привести к вызывая тот же слушателю 1 раз или N раз, или быть ошибка, это другой вопрос)

Это просто вопрос традиции? В любом случае наборы - это какие-то списки под капотом. Существуют ли различия в производительности? Итерируется ли через List быстрее или медленнее, чем итерация через Set? Делает ли он более или менее память? Различия, безусловно, почти незначительны.

+10

Потому что это список? : p – kennytm

ответ

8

Одна из важных причин, по которой списки слушателей, которые являются списками (вместо наборов), также объясняет, почему вы часто видите, что они повторяются в обратном порядке. Обычный сценарий включает слушателя, удаляющего себя как слушателя, когда он уведомляется о некоторых изменениях. Если слушатели были сохранены в виде списка и переименованы вперёд (или сохранены в виде набора и итерированы в некотором неопределенном порядке), удаление себя в качестве слушателя вызовет исключение ConcurrentModificationException.

Таким образом, слушатели хранятся в виде списка и уведомляются в обратном порядке. Затем, если слушатель удаляет себя из списка слушателей, когда он уведомляется, он не вызывает исключение ConcurrentModificationException или не меняет индексы других, но не уведомленных слушателей.

+0

Что делать, если вы не заботитесь о заказе? –

+0

Если ваши слушатели когда-либо убираются в ответ на уведомление, вам следует позаботиться. В противном случае вы ничего не потеряли, сохранив заказ. – Mark

+0

если они уберутся, зачем мне это делать? Я думаю, что для большинства случаев нормально использовать набор. слушатели не должны обычно делать предположения о том, когда они будут вызваны по сравнению с другими слушателями. Может быть, SkipList - это решение в середине для этого? weird, я не могу найти для него класс Java. –

1

Какой набор? Должны ли все слушатели использовать equals и hashCode, чтобы использовать хеш-набор или задан ли хэш-хэш? Является ли прецедент добавлением слушателя в список в два раза сложнее? Существует ли простой механизм для обеспечения безопасности набора для добавления или удаления прослушивателей во время вызовов их обработчиков?

Возможно, существуют некоторые различия в производительности, но, безусловно, существует более сложный дизайн, и это вынуждает множественное добавление-множественное удаление решения в библиотеку, а не оставить его в приложении.

+0

Я думаю, что набор хэш-идентификации идентичен. Но, предоставленный, нет «CopyOnWriteIdentityHashSet», доступного из коробки, поэтому использование общей идиомы списка может быть просто проще в достижении правильного конечного результата. –

+0

Но: действительно есть CopyOnWriteArraySet в Java 6, который является потокобезопасным («Обход через итераторы выполняется быстро и не может встретить помехи от других потоков»). Согласно http://java.sun.com/javase/6/docs/technotes/guides/collections/changes5.html «Эта реализация хорошо подходит для поддержки списков обработчиков событий, которые должны предотвращать дубликаты». –

+1

@Joonas Поскольку обработчики Swing вызываются в потоке Swing, проблема всегда изменяла базовую коллекцию и аннулировала итератор, а не одновременные обновления. Но если вы хотите использовать семантику, вы, конечно, можете использовать набор для копирования на запись. –

0

Вы совершенно правы. Слушатели должны быть добавлены к наборам. Как вы сказали, добавление слушателя более одного раза не имеет смысла. Кроме того, вы не будете полагаться на порядок слушателей, если будете использовать наборы. И это самое главное: НЕ ДОЛЖНО полагаться на это, если вы серьезно относитесь к разработке программного обеспечения и к каждому принципу, который мы выяснили, чтобы привести нас к лучшему дизайну: Изоляция, Независимость, Ответственность.

Каждый аспект, упомянутый здесь (многопоточность, производительность, ...), должен подчиняться себе в первую мысль, но может быть нарушен после того, как у вас есть веские причины. И я имею в виду ОЧЕНЬ хорошие причины.

К слову, это плохая практика, позволяющая слушателю удалить себя. Добавление и удаление должно быть симметричным. Поэтому слушатель должен быть удален через объект, который его зарегистрировал. Если у вас много слушателей, вы скоро застрянете.

Смежные вопросы