Как реализовать полный шаблон Observer в PHP - PullRequest
5 голосов
/ 16 июня 2011

Шаблон проектирования Observer - это решение для слабой связи объектов, чтобы они могли работать вместе.В PHP вы можете легко реализовать это, используя только два класса .

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

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

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

Этот класс загрузки файлов может иметь три места, где он должен уведомить прослушивающие классы, что что-то произошло.

  • Ошибка при загрузке (класс регистрации предупреждений)
  • Успешная загрузка (класс предупреждений)
  • Успешная загрузка и файл образа (класс изменения размера предупреждений)

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

Одна мысль состоит в том, что я мог бы при вызове указать, какой тип события наблюдается:

$this->notifyObservers('upload.error', this);

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

function observe($type, $object)
{
    if($type === 'upload.error') $this->dosomething();
    elseif($type === 'something.else') $this->otherthing();
    ...etc...
}

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

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

1 Ответ

5 голосов
/ 16 июня 2011

Наблюдатели на самом деле не связаны с классом, который они наблюдают. Связь между обработчиком наблюдателя и наблюдаемым объектом осуществляется с использованием буквенных строковых значений (например, «upload.error»), что означает, что:

  1. Если вы хотите наблюдать за конкретным объектом, вы должны заранее знать названия событий, которые он будет публиковать; это «соединение», которое вам не нравится.
  2. С другой стороны, если вас интересует только конкретное событие, вы можете наблюдать за любым типом объекта для этого события, не зная об этом объекте.

Пункт 2 выше - это преимущество, которое вас волнует, но что делать с пунктом 1?

Если вы подумаете об этом, должен быть какой-то способ различения обратных вызовов к одному и тому же наблюдателю, если они представляют разные происходящие события. Эти «идентификаторы», независимо от их формы, должны быть упакованы либо в наблюдаемый объект, либо быть частью кода библиотеки наблюдателя.

В первом случае (внутри наблюдаемого объекта) вам, вероятно, понадобится способ для наблюдателей спросить: "Вы когда-нибудь публиковали событие X?" перед началом наблюдения за целью для этого события. Цель может ответить на этот вопрос просто отлично. Это оставляет горький вкус связи, но если вы хотите, чтобы какой-либо объект наблюдал какой-либо другой, и вы не представляете, что вы будете наблюдать заранее, я не думаю, что вы можете добиться большего.

Во втором подходе в вашей библиотеке будет определен ряд известных событий (например, const внутри класса?). Предположительно такой список событий может быть составлен, потому что библиотека занимается конкретным доменом приложения, и этот домен предлагает очевидный выбор для событий. Затем классы, как внутренние для вашей библиотеки (которые в конечном итоге будут наблюдаться), так и внешние для нее (наблюдатели, подключающиеся к платформе) будут использовать эти идентификаторы для различения событий. Многие основанные на обратном вызове API (такие как Win32) используют подход, практически идентичный этому.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...