Почему списки списков слушателей?

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

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

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

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

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

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