Как эффективно реализовать шаблон наблюдателя, если объект представляет собой огромный контейнер? - PullRequest
3 голосов
/ 05 июня 2009

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

Как бы вы реализовали механизм обновления, чтобы он был быстрым в отношении вставки и удаления элементов, когда вы сохраняете огромное количество объектов в вашем контейнере? В частности,

  • Вы бы использовали контейнер такого же типа в локальной копии наблюдателей?
  • Есть ли разумный выбор контейнера, который должны использовать наблюдатели? (Например, было бы быстрее, скажем, всегда использовать сбалансированные деревья, даже если вы наблюдаете связанный список?)
  • как быстро перевести итератор в наблюдаемый контейнер в итератор в контейнер наблюдателя? (Тривиально для массивов, сложно для связанных списков?)

Если ваш контейнер, например, является связанным списком, вы можете вставлять элементы в постоянное время. Если m наблюдателям приходится перебирать список, содержащий n элементов, обновление занимает ожидаемое время O (n * m).

Если ваш контейнер является массивом, то для изменения элемента требуется постоянное время, а для обновления m наблюдателей требуется O (m), если вы передаете индекс элемента, O (n * m), если наблюдатели должны выполнять итерацию по массиву. 1017 *

Если это поможет, рассмотрите следующие примеры:

Пример 1. Вы пишете операционную систему. Предмет, который вы хотели бы наблюдать, - это файловая система и ее файлы. Ваши представления - это файловый менеджер, индексатор и другие приложения. Вы хотите обновить наблюдателей при добавлении, удалении или изменении файлов.

Пример 2. Вы пишете приложение адресной книги, которое должно иметь возможность обрабатывать город размером с Нью-Йорк. Предмет, который вы хотели бы наблюдать, - это контейнер ваших записей (человек с его адресом, номерами телефонов, электронной почтой ...). У ваших наблюдателей есть несколько просмотров, которые должны обновляться автоматически при добавлении, удалении или изменении записи. (Можно нарисовать один вид, содержащий список людей, живущих на 53-м месте, а другой - нарисовать точки на карте для каждого человека, чья фамилия Доу).

Как вы справляетесь со случаем, когда полное поддерево каталога удалено или что «53-й St» переименован в «Dijkstra St»?

Ответы [ 2 ]

4 голосов
/ 05 июня 2009

Каким-то образом вы должны превратить контейнер в тему.

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

[РЕДАКТИРОВАТЬ] Поскольку вы просите эффективный способ, общий ответ "это зависит". Шаблоны проектирования не имеют решения «один размер подходит всем». Это общие правила, как подходить к проблеме. То, как вам нужно реализовать правила в конкретной ситуации, - это то, что вы решаете, находясь в ситуации.

Как правило, если ваши наблюдатели должны идентифицировать небольшие изменения (например, изменение атрибута или добавление элемента), сообщение с уведомлением должно содержать достаточно информации, чтобы они могли сделать это эффективно. Поэтому, если у вас большой список и вставка, отправьте список и индекс нового элемента плюс «элемент как вставленный».

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

Кроме того, у вас может быть «изменить элемент в списке». Это означает, что запрещено менять предметы напрямую, вы всегда должны пользоваться сервисом. Затем служба может работать как субъект и отправлять уведомления с элементом, старым и измененным значением и, возможно, с индексом в списке.

[EDIT2] Общее правило - собирать как можно больше информации об изменениях и передавать ее наблюдателям. Но это действительно зависит от вашей конкретной проблемы. Допустим, наблюдатель сидит на удаленной машине. В этом случае нет эффективного способа отправить ему весь список. Вы можете отправить только «элемент X был вставлен» и надеяться, что этого достаточно. Если у контейнера нет возможности замечать изменения (например, новые веб-страницы на веб-сайте), контейнер должен снова и снова пересматривать весь сайт, чтобы найти изменения, которые он затем может эффективно сообщить наблюдателям.

Опять же, детали действительно зависят от конкретной ситуации. Google запускает тысячи веб-пауков, которые посещают миллионы веб-страниц каждый час. Долгое время это было «эффективно» (как «единственным способом»). Некоторое время назад был реализован протокол "карта сайта", который позволяет администраторам превращать свои веб-сайты в темы, которые могут сообщать наблюдателю Google об изменениях.

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

[EDIT3] Вот несколько примеров использования шаблона наблюдателя:

  • Многие пользовательские интерфейсы используют этот шаблон для распространения событий среди заинтересованных сторон. В Qt у вас есть центральное место, где все субъекты могут регистрировать свои сигналы (уведомления, которые они будут отправлять) и где наблюдатели могут прикрепляться к объектам. Это означает, что есть единственное место, где все соединения управляются. Преимущество состоит в том, что вам не нужно добавлять эту структуру данных к каждому объекту. Кроме того, объекты извне (не-Qt объекты) могут отправлять и получать сообщения. Поскольку все в одном месте, эту структуру данных можно легко оптимизировать. Недостатком является то, что эта структура может стать очень большой, поэтому отправка сообщения займет больше времени, когда в нем участвует больше сторон (даже тех, которые совершенно не связаны).

  • Google использует протокол карты сайта для превращения веб-сайтов в темы, поскольку это гораздо эффективнее, чем обходить весь сайт снова и снова, даже если вы запрашиваете только время последнего изменения URL (HTTP HEAD вместо HTTP GET ).

  • Файловые системы в Windows и Linux предлагают уведомления, чтобы сообщить приложениям о новых или удаленных файлах. Основная проблема заключается в том, что должно происходить, когда файлы изменяются, когда приложение не запускается. Допустим, у вас есть приложение, которое поддерживает контрольные суммы файлов в каталоге. Очевидно, что вы хотели бы знать об изменениях, когда приложение не работало, но это означало бы, что служба уведомлений должна будет отслеживать последние отправленные изменения. Так что здесь, приложение должно прочитать все дерево при запуске, чтобы увидеть все, что оно могло пропустить, и оно должно использовать шаблон наблюдателя для изменений, происходящих во время работы.

  • Почтовый клиент является наблюдателем. Он сообщит почтовому серверу идентификатор последнего увиденного им письма, а сервер сообщит ему о любых новых письмах.

  • Когда у вас много изменений атрибутов в сложной модели, обычно это единственный способ централизовать все изменения (заставить их проходить через одно место) и прикрепить туда наблюдателей (вместо того, чтобы прикреплять N наблюдателей к M индивидууму). объекты). В этой реализации наблюдатели могут сказать «меня интересует любое изменение в любом месте» или «изменение поля X в любом предмете» или «любое изменение в предмете Y» (последнее обычно удваивается как «изменение поля» X в теме Y "- наблюдатель просто игнорирует изменения полей! = X).

1 голос
/ 05 июня 2009

Почему бы не сам шаблон наблюдателя?

Субъект должен информировать наблюдателя об интересных событиях. Затем наблюдатель направляет его заинтересованным лицам (подписчикам).

Природа субъекта здесь не имеет никакого значения. (Если я не понял ваш вопрос неправильно).

...