2010-05-30 10 views
11

¿Por qué las listas de escucha (por ejemplo, en Java las que usan addXxxListener() y removeXxxListener() para registrar y anular el registro de escuchas) llamaron a listas y generalmente se implementaron como Lists? No sería un Set ser un mejor ajuste, ya que en el caso de los oyentes no¿Por qué las listas de oyentes son listas?

  • No importa en qué orden las llaman (aunque es muy posible que este tipo de necesidades, pero son casos especiales, los mecanismos ordinarios de escucha hacer ningún tipo de garantías), y
  • No hay necesidad de registrar la misma escucha más de una vez (ya sea haciendo que deberían dar lugar a llamar a la misma escucha 1 veces o n veces, o sea un error, es otra cuestión)

¿Es solo una cuestión de tradición? Los sets son algún tipo de listas bajo el capó de todos modos. ¿Hay diferencias de rendimiento? Está iterando a través de un List más rápido o más lento que iterar a través de un Set? ¿Toma más o menos memoria? Las diferencias son ciertamente casi insignificantes.

+10

porque es un list'ener? : p – kennytm

Respuesta

8

Una razón importante para que las listas de oyentes sean listas (en lugar de conjuntos) también explica por qué a menudo se ve que se repiten al revés. Un escenario común implica que un oyente se elimine como oyente cuando se le notifica algún cambio. Si los oyentes se almacenaron como una lista e iteraron hacia delante (o se almacenaron como un conjunto y se repitieron en un orden indeterminado), al eliminarse como un oyente se generará una ConcurrentModificationException.

Por lo tanto, en su lugar, los oyentes se almacenan como una lista y se notifican en orden inverso. Entonces, si un oyente se elimina de la lista de oyentes cuando es notificado, no causa una excepción de modificación simultánea o cambia los índices de los otros oyentes no notificados aún.

+0

¿Qué sucede si no le importa el pedido? –

+0

Si sus oyentes alguna vez se eliminan a sí mismos en respuesta a una notificación, debe preocuparse. De lo contrario, no ha perdido nada al preservar el orden. – Mark

+0

si se eliminan, ¿por qué debería importarme? Creo que para la mayoría de los casos, está bien usar un conjunto. los oyentes usualmente no deben hacer suposiciones sobre cuándo serán llamados en comparación con otros oyentes. ¿Quizás una lista de exclusión es la solución en el medio para esto? raro, no puedo encontrar una clase de Java para eso. –

1

¿Qué tipo de conjunto? ¿Deberían todos los oyentes implementar equals y hashCode para que se use un conjunto de hash, o un hash de identidad establecido? ¿El caso de uso de agregar un oyente a una lista vale dos veces la complejidad? ¿Existe un mecanismo tan simple para hacer que el conjunto sea seguro contra agregar o eliminar oyentes durante las llamadas a sus controladores?

Puede haber algunas diferencias de rendimiento, pero sin duda hay un diseño más complicado, y obliga a la decisión de quitar varios elementos múltiples en la biblioteca en lugar de dejarlo en la aplicación.

+0

Creo que un conjunto de hash de identidad sería apropiado. Pero, sin embargo, no hay ningún "CopyOnWriteIdentityHashSet" disponible de fábrica, por lo que utilizar el idioma común de la lista puede ser simplemente más simple para lograr el resultado final correcto. –

+0

Pero: de hecho hay un CopyOnWriteArraySet en Java 6, que es seguro para subprocesos ("Cruce a través de iteradores es rápido y no puede encontrar interferencia de otros subprocesos"). De acuerdo con http://java.sun.com/javase/6/docs/technotes/guides/collections/changes5.html "Esta implementación es adecuada para mantener listas de controladores de eventos que deben evitar duplicados". –

+1

@Joonas Dado que los manejadores Swing se invocan en el subproceso Swing, el problema siempre fue modificar la colección subyacente e invalidar el iterador en lugar de las actualizaciones simultáneas. Pero si desea esa semántica, sin duda podría utilizar un conjunto de copia sobre escritura. –

0

Tiene toda la razón. Los oyentes deben agregarse a los conjuntos. Como dijiste, agregar un oyente más de una vez no tiene sentido. Además, uno no dependerá del orden de los oyentes si usa conjuntos. Y eso es lo más importante: uno NO DEBE confiar en él si toma en serio el desarrollo del software y cada principio que descubrimos nos lleva a un mejor diseño: Aislamiento, Independencia, Responsabilidad.

Todos los aspectos mencionados aquí (multi threading, rendimiento, ...) tienen que subordinarse en el primer pensamiento, pero pueden romperse después si tiene buenas razones. Y me refiero a MUY buenas razones.

Por cierto: es una mala práctica dejar que el oyente se quite solo. Agregar y eliminar debe ser simétrico. Entonces el oyente debe ser eliminado a través del objeto que lo registró. Si tiene muchos oyentes involucrados, se quedará atrapado pronto.

Cuestiones relacionadas