Почему шаблон наблюдателя должен быть устаревшим?

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

Мартин Одерски и друзья писали длинную бумагу с особо заманчивым названием "Устаревший шаблон наблюдателя" , и я еще не успел чтобы прочитать его.

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

В начале я нашел одну (интересную) критику бумаги здесь.

Ответ 1

Цитата прямо из в документе:

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

var path: Path = null
val moveObserver = { (event: MouseEvent) =>
   path.lineTo(event.position)
   draw(path)
}
control.addMouseDownObserver { event =>
   path = new Path(event.position)
   control.addMouseMoveObserver(moveObserver)
}
control.addMouseUpObserver { event =>
   control.removeMouseMoveObserver(moveObserver)
   path.close()
   draw(path)
}

Приведенный выше пример, и, как мы будем утверждать, наблюдатель как определено в [25] в целом, нарушает впечатляющий состав важных принципов разработки программного обеспечения:

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

Инкапсуляция Поскольку переменная состояния Path выходит из области действия наблюдателей картина наблюдателя ломает инкапсуляцию.

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

Разделение проблем Вышеуказанные наблюдатели не только отслеживают путь мыши, но также вызов команды рисования или в более общем плане, включают две различные проблемы в такое же расположение кода. Часто предпочтительнее отделять проблемы построения пути и отображения его, например, как в шаблоне модели-просмотра (MVC) [30].

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

Однородность Различные способы установки разных наблюдателей уменьшить однородность кода.

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

Управление ресурсами Жизненный цикл наблюдателей должен быть управляемых клиентами. Из-за соображений производительности, мы хотим наблюдать за событиями перемещения мыши только во время перетащите. Поэтому нам необходимо явно установить и удалите наблюдателя перемещения мыши, и нам нужно вспомните точку установки (см. выше).

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

[25] Э. Гамма, Р. Хельм, Р. Джонсон и Дж. Влиссидес. дизайн шаблоны: элементы многоразового объектно-ориентированного программного обеспечения. Addison-Wesley Longman Publishing Co., Inc., Бостон, Массачусетс, USA, 1995. ISBN 0-201-63361-2.

Ответ 2

Я считаю, что шаблон Observer имеет стандартные недостатки, связанные с развязкой вещей. Субъект отделяется от Observer, но вы не можете просто взглянуть на его исходный код и узнать, кто его наблюдает. Закодированные зависимости обычно легче читать и думать, но их сложнее модифицировать и повторно использовать. Это компромисс.

Что касается бумаги, она не касается самого шаблона Observer, а его конкретного использования. В частности: несколько объектов-наблюдателей без сохранения состояния на один наблюдаемый объект. У этого есть очевидный недостаток отдельных наблюдателей, которым необходимо синхронизировать друг с другом ("Поскольку наблюдатели не имеют гражданства, нам часто нужно несколько из них, чтобы имитировать конечный автомат, как в примере перетаскивания. Мы должны сэкономить государство, в котором оно доступно всем задействованным наблюдателям например, в переменном пути выше. ")

Указанный недостаток специфичен для такого типа использования, а не для самого шаблона Observer. Вы могли бы также создать единый объект (stateful!) Observer, который реализует все методы OnThis, OnThat, OnWhatever и избавиться от проблемы имитации конечного автомата по многим объектам без гражданства.

Ответ 3

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

Шаблон наблюдателя интуитивно ошибочен: наблюдаемый объект знает, кто наблюдает (Subject < > - Observer). Это противоречит реальной жизни (в сценариях, основанных на событиях). Если я кричу, я понятия не имею, кто слушает; если молния, бьет пол... молния не знает, что есть пол, пока он не ударит!. Только наблюдатели знают, что они могут наблюдать.

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

IMO, такой слой, как "Окружающая среда", является ответственным за принятие событий и уведомление пострадавшего. (ИЛИ смешивает событие и генератор этого события)

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

В моем понимании шаблон Observer объединяет среду и субъект.

PS. ненавижу вводить абзацы абзацев абзацев!: P