В общем, да, слабые ссылки должны быть использованы. Но сначала мы должны понять, что вы подразумеваете под «слушателями событий».
Callbacks
В некоторых стилях программирования, особенно в контексте асинхронных операций, принято представлять часть вычисления в виде обратного вызова, который выполняется для определенного события. Например, Promise
[ 1 ] может иметь then
метод, который регистрирует обратный вызов после завершения предыдущего шага:
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
Здесь зарегистрированные обратные вызовы then
должны удерживаться сильными ссылками, поскольку обещание (источник события) является единственным объектом, содержащим ссылку на обратный вызов. Это не проблема, поскольку само обещание имеет ограниченный срок службы и будет собирать мусор после завершения цепочки обещаний.
Шаблон наблюдателя
В схеме наблюдателя субъект имеет список зависимых наблюдателей. Когда субъект входит в какое-то состояние, наблюдатели уведомляются согласно некоторому интерфейсу. Наблюдатели могут быть добавлены в тему и удалены из нее. Эти наблюдатели не существуют в семантическом вакууме, но ждут событий с какой-то целью.
Если эта цель больше не существует, наблюдатели должны быть удалены от субъекта. Даже в языках с мусором это удаление может быть выполнено вручную. Если нам не удастся удалить наблюдателя, он будет поддерживаться через ссылку субъекта на наблюдателя и вместе с ним все объекты, на которые ссылается наблюдатель. Это приводит к потере памяти и снижению производительности, поскольку (теперь бесполезный) наблюдатель все равно будет уведомлен.
Слабые ссылки исправляют эту утечку памяти, поскольку они позволяют наблюдателю собирать мусор. Когда субъект идет вокруг, чтобы уведомить всех наблюдателей и обнаруживает, что одна из слабых ссылок на наблюдателя пуста, эту ссылку можно безопасно удалить. Альтернативно, слабые ссылки могут быть реализованы таким образом, чтобы субъект мог зарегистрировать обратный вызов очистки, который удалит наблюдателя при сборе.
Но обратите внимание, что слабые ссылки - это всего лишь лейкопластырь, который ограничивает урон, забывая удалить наблюдателя. Правильным решением было бы убедиться, что наблюдатель удален, когда он больше не нужен. Варианты включают в себя:
Делаем это вручную, но это подвержено ошибкам.
Использование чего-то похожего на try-with-resource в Java или using
в C #.
Детерминированное разрушение, например, через идиому RAII. Обратите внимание, что в языке с детерминированной сборкой мусора для этого может потребоваться слабая ссылка субъекта на наблюдателя для запуска деструктора.