In generale, sì, dovrebbero essere usati riferimenti deboli. Ma prima dobbiamo essere chiari su cosa intendi per "ascoltatori di eventi".
callback
In alcuni stili di programmazione, specialmente nel contesto di operazioni asincrone, è comune rappresentare una parte di un calcolo come un callback che viene eseguito su un determinato evento. Ad esempio un Promise
[ 1 ] può avere un then
metodo che registra un callback al completamento del passaggio precedente:
promise =
Promise.new(async_task) # - kick off a task
.then(value => operation_on(value)) # - queue other operations
.then(value => other_operation(value)) # that get executed on completion
... # do other stuff in the meanwhile
# later:
result = promise.value # block for the result
Qui, i callback registrati da then
devono essere mantenuti da forti riferimenti, poiché la promessa (la fonte dell'evento) è l'unico oggetto che contiene un riferimento al callback. Questo non è un problema in quanto la promessa stessa ha una durata limitata e sarà raccolta rifiuti dopo il completamento della catena di promesse.
Modello di osservatore
Nel modello di osservatore, un soggetto ha un elenco di osservatori dipendenti. Quando il soggetto entra in uno stato, gli osservatori vengono avvisati secondo una certa interfaccia. Gli osservatori possono essere aggiunti e rimossi dall'argomento. Questi osservatori non esistono in un vuoto semantico, ma stanno aspettando eventi per qualche scopo.
Se questo scopo non esiste più, gli osservatori dovrebbero essere rimossi dall'argomento. Anche nelle lingue raccolte con immondizia, questa rimozione potrebbe dover essere eseguita manualmente. Se non riusciamo a rimuovere un osservatore, sarà mantenuto in vita tramite il riferimento dal soggetto all'osservatore, e con esso tutti gli oggetti a cui l'osservatore fa riferimento. Ciò spreca memoria e peggiora le prestazioni poiché l'osservatore (ora inutile) verrà comunque informato.
Riferimenti deboli risolvono questa perdita di memoria, in quanto consentono all'osservatore di essere spazzato via. Quando il soggetto va in giro per avvisare tutti gli osservatori e scopre che uno dei riferimenti deboli a un osservatore è vuoto, quel riferimento può essere rimosso in modo sicuro. In alternativa, i riferimenti deboli potrebbero essere implementati in modo da consentire al soggetto di registrare un callback di cleanup che rimuoverà l'osservatore al momento della raccolta.
Ma nota che i riferimenti deboli sono solo un cerotto che limita il danno dimenticando di rimuovere un osservatore. La soluzione corretta sarebbe quella di assicurarsi che un osservatore venga rimosso quando non è più necessario. Le opzioni includono:
Farlo manualmente, ma è soggetto a errori.
Usando qualcosa di simile per provare con risorse in Java o using
in C #.
Distruzione deterministica, come attraverso il linguaggio RAII. Si noti che in un linguaggio con garbage collection deterministica, ciò potrebbe richiedere riferimenti deboli dal soggetto all'osservatore per attivare il distruttore.