Por lo general, los oyentes de eventos no deberían sobrevivir a los objetos que los registraron.
¿Significa que los oyentes de eventos deberían estar sujetos a referencias débiles por defecto (almacenadas en colecciones débiles por las que los oyentes objeto están registrados)?
¿Hay casos válidos en los que el oyente debería sobrevivir a su creador?
¿O tal vez una situación como esa es un error y no debería permitirse?
api-design
event
mrpyo
fuente
fuente
Respuestas:
¿Por qué los oyentes de eventos no deberían sobrevivir al objeto que los registró? Parece que está asumiendo que los oyentes de eventos deberían registrarse por métodos de controles (si tomamos el ejemplo de la GUI), o más precisamente, métodos por objetos de clases que heredan los controles del kit de herramientas de la GUI. Eso no es una necesidad: podría, por ejemplo, usar un objeto especializado para registrar oyentes de eventos y luego deshacerse de ese objeto.
Además, si los oyentes de eventos se derivaron débilmente, tendría que mantener referencias a ellos incluso si nunca usa esa referencia. De lo contrario, el oyente se recogerá en un momento aleatorio. Entonces, tenemos un error que es
Y si evitar ese error no es un incentivo suficiente, aquí hay algunos más:
Tendrá que pensar en un nombre para cada oyente que cree.
Algunos idiomas usan análisis estático que generarán una advertencia si tiene un campo de miembro privado que nunca se escribe o nunca se lee. Tendrá que usar un mecanismo para anular eso.
El oyente de eventos hace algo, y una vez que el objeto que tiene su fuerte referencia se recopila, dejará de hacer eso. Ahora tiene algo que afecta el estado del programa y depende del GC, lo que significa que el GC afecta el estado concreto del programa. ¡Y esto es MALO !
El manejo de referencias débiles es más lento, ya que tiene otro nivel de indirección y necesita verificar si se recopiló la referencia. Esto no sería un problema si fuera necesario tener oyentes de eventos con referencias débiles, ¡pero no lo es!
fuente
En general, sí, deben usarse referencias débiles. Pero primero tenemos que tener claro lo que quiere decir con "oyentes de eventos".
Devoluciones de llamada
En algunos estilos de programación, especialmente en el contexto de operaciones asincrónicas, es común representar una parte de un cálculo como una devolución de llamada que se ejecuta en un evento determinado. Por ejemplo, un
Promise
[ 1 ] puede tener unthen
método que registre una devolución de llamada al completar el paso anterior:Aquí, las devoluciones de llamada registradas por
then
deben ser retenidas por referencias fuertes, ya que la promesa (el origen del evento) es el único objeto que contiene una referencia a la devolución de llamada. Esto no es un problema, ya que la promesa en sí misma tiene una vida limitada, y se recolectará basura una vez que se complete la cadena de promesas.Patrón de observador
En el patrón de observador, un sujeto tiene una lista de observadores dependientes. Cuando el sujeto entra en algún estado, los observadores son notificados de acuerdo con alguna interfaz. Los observadores pueden agregarse y eliminarse del sujeto. Estos observadores no existen en un vacío semántico, pero están esperando eventos para algún propósito.
Si este propósito ya no existe, los observadores deberían ser retirados del tema. Incluso en los idiomas recolectados de basura, esta eliminación podría tener que realizarse manualmente. Si no eliminamos un observador, se mantendrá vivo a través de la referencia del sujeto al observador, y con él todos los objetos a los que hace referencia el observador. Esto desperdicia memoria y degrada el rendimiento ya que el observador (ahora inútil) aún será notificado.
Las referencias débiles corrigen esta pérdida de memoria, ya que permiten que el observador sea recolectado como basura. Cuando el sujeto se da la vuelta para notificar a todos los observadores y encuentra que una de las referencias débiles a un observador está vacía, esa referencia se puede eliminar de forma segura. Alternativamente, las referencias débiles podrían implementarse de una manera que permita al sujeto registrar una devolución de llamada de limpieza que eliminará al observador al momento de la recolección.
Pero tenga en cuenta que las referencias débiles son solo una curita que limitan el daño al olvidar quitar un observador. La solución correcta sería asegurarse de que se elimine un observador cuando ya no sea necesario. Las opciones incluyen:
Hacerlo manualmente, pero es propenso a errores.
Usar algo parecido a probar con recursos en Java o
using
en C #.Destrucción determinista, como a través del idioma RAII. Tenga en cuenta que en un lenguaje con recolección de basura determinista, esto aún podría requerir referencias débiles del sujeto al observador para activar el destructor.
fuente