Когда наблюдаемый шаблон вызывает проблемы с ГХ - PullRequest
3 голосов
/ 11 ноября 2009

На языке с поддержкой GC, когда наблюдатель подписывается на события субъекта, фактически субъект получает ссылку наблюдателя.

Так что, прежде чем оставить наблюдателя, он должен сначала отменить подписку. В противном случае, поскольку на него все еще ссылаются субъекты, он никогда не будет собирать мусор.

Обычно есть 3 решения:

  1. Отказ от подписки вручную
  2. Слабая ссылка.

Они оба вызывают другие проблемы.

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

Я имею в виду, этот шаблон описывает вещи настолько естественным образом, что Вы вряд ли найдете что-то лучшее.

Что вы думаете об этом?

Ответы [ 3 ]

1 голос
/ 11 ноября 2009

В этом сценарии вы можете использовать finalize() в Java. finalize() - плохая идея, когда у есть для освобождения ресурса (например, соединения с БД), потому что это влияет на внешнюю систему. В вашем случае объект, который установил наблюдатель, будет GC'd во время выполнения вашего приложения, а затем будет вызван finalize(), и он может отменить подписку наблюдателя.

Не совсем то, что вы хотите, но кто-то должен решить, что «теперь можно отписаться». Это происходит либо тогда, когда ваш объект уходит (но он уже должен убить всех наблюдателей), либо объект, который установил наблюдателя.

Если ваше приложение неожиданно завершает свою работу, не повредит, что finalize() может не вызываться в этом случае.

0 голосов
/ 30 сентября 2010

Рассмотрим сценарий объекта, который подсчитывает, как часто меняется какая-то наблюдаемая вещь. Существует два типа ссылок на объект: (1) ссылки на объекты, которые заинтересованы в подсчете; (2) те, которые используются наблюдаемыми вещами, которые на самом деле не заинтересованы в подсчете, но нуждаются в его обновлении. Объекты, которые заинтересованы в подсчете, должны содержать ссылку на объект, который в свою очередь содержит ссылку на объект, который управляет подсчетом. Сущности, которые должны будут обновить счетчик, но не заинтересованы в нем, должны просто содержать ссылки на второй объект.

Если первый объект содержит финализатор, он будет запущен, когда объект выйдет из области видимости. Это может привести к тому, что второй объект откажется от подписки, но, вероятно, он не должен быть отписан напрямую. Отказ от подписки, вероятно, потребует получения блокировки, и финализаторы не должны ждать блокировок. Вместо этого финализатор первого объекта, вероятно, должен добавить этот объект в связанный список, поддерживаемый с помощью Interlocked.CompareExchange, а некоторые другие потоки должны периодически запрашивать этот список для объектов, нуждающихся в подписке.

Примечание: между прочим: если первый объект содержит ссылку на второй объект, последний будет гарантированно существовать при выполнении финализатора для первого объекта, но он не будет гарантированно находиться в любом конкретное состояние. Нить очистки не должна пытаться с ней что-либо делать, кроме как отписаться.

0 голосов
/ 11 ноября 2009

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

Тот факт, что вы не отказываетесь от подписки, является плохим дизайном, ИМО. Не вините шаблон за плохую реализацию.

Шаблон наблюдателя работает хорошо, но если вы хотите смягчить некоторые проблемы, вы можете использовать AOP для реализации: http://www.cin.ufpe.br/~sugarloafplop/final_articles/20_ObserverAspects.pdf

...