Каковы преимущества шаблона делегата над шаблоном наблюдателя?


9

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


4
Что вы имеете в виду под «моделью делегата»? Если вы говорите о чем-то вроде делегатов .net, вы можете иметь столько подписчиков, сколько захотите.
CodesInChaos

Ответы:


7

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

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

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

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


6

Вы смотрите на вещи неправильно. Наблюдатель видит, что происходит определенное событие. Это не влияет на это, или не владеет им. Делегат обрабатывает определенное событие и владеет обработчиком, даже если делегат владеет интерфейсом к событию.


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

5
@MarjanVenema - если объект А не делегируя ответственность за события на объект B, вы не используете шаблон делегирования: вы используете шаблон наблюдателя только с одним наблюдателем.
Теластин

Да, это то, о чем я думал. Я понял, что делегированными должны быть типы сигнатур событий, которые будут использоваться подписчиком события «OnWhwhat». Очевидно, что делегаты в C # не являются однопользовательскими, как, например, в Delphi.
Марьян Венема

@Marjan Venema «Делегат на самом деле является не чем иным, как наблюдателем события». - это зависит от того, на каком языке вы говорите. В Задаче C некоторые делегаты отвечают за предоставление данных, например делегатов данных, а объект, в котором отсутствует делегат данных, не имеет данных для представления. В этих случаях происходит делегирование, в отличие от просто наблюдения чего-либо.
occulus

1
@occulus: спасибо за разъяснения. Жаль, что языки не могут договориться о терминологии ... Говорить о программировании без языкового подхода становится немного трудно, когда люди понимают разные вещи для одних и тех же слов.
Марьян Венема

4

Это вопрос нескольких компромиссов.

Компромиссы:

  • гибкость (с точки зрения наличия n> 1 делегатов / наблюдателей)
  • стоимость отправки сообщения
  • устойчивость (способность поддерживать недоступность делегата / наблюдателей)
  • простота использования

Шаблон делегата:

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

Шаблон наблюдателя:

  • очень гибкая - добавление n> 1 наблюдателей ожидается в дизайне
  • стоимость отправки сообщения зависит от количества наблюдателей, O (n), то есть n наблюдателей занимают n времени и сообщений (по крайней мере, в наивной реализации)
  • как правило, отказоустойчивые - обычно от наблюдателей не ожидается никакой работы со стороны отправителя. То есть, даже если нет наблюдателя, отправитель не затронут
  • может стать довольно сложным для восприятия, в частности, ожидается, что наблюдатели будут реагировать на сообщения (имеет ли значение порядок? какой наблюдатель отвечает каким образом?)

1

Шаблон делегата, насколько я понимаю, известен как механизм обработки событий в других языках, например Delphi. Как таковая, это просто реализация шаблона наблюдателя с основным ограничением: только один слушатель за раз.

Недостаток обработчиков событий или делегатов очевиден: только один наблюдатель.

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


А? Делегат C # - это просто сигнатура метода в виде типа переменной (эквивалентно, например, int (*my_int_f)(int)в C). Я всегда думал, что они могли бы сделать это проще для понимания, сделав его более похожим на struct / enum. Событие - это ловушка для гибкого массива слушателей, использующего одну подпись делегата. Вы могли бы сделать это без события (именно поэтому я предполагаю, что OP означало паттерн делегирования, который сильно отличается), но язык делает его проще для вас.
фунтовые

хмм. Пока не очень хорошо разбираюсь в C #. Я понял, что делегаты эквивалентны типам сигнатур событий, которые используются событиями «OnWhwhat», например, в Delphi. Таким образом, события C # могут быть подписаны несколькими слушателями?
Marjan Venema

Общее действие <T> является делегатом. Это не имеет ничего общего с событиями, это переменная, которая передается. И да, несколько слушателей могут прослушивать одно событие.
фунтовые

Хорошо, спасибо, надеюсь, я смогу сделать это прямо ... :-) Взял ссылку на C # и сосредоточился больше на механизме событий.
Марьян Венема

1

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

Как работают делегация и наблюдатель

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

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

Преимущество делегирования

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

Недостаток делегирования

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

Когда выбрать делегацию?

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

Например, вам нужен класс / объект для обработки всплывающих окон для конкретной ошибки. Существует не так много причин, почему во время выполнения вам нужно было бы переключаться между тем, кто обрабатывает конкретную ошибку, поэтому имеет смысл делегировать ошибку «Недостаточно памяти» одному объекту. Создание массива потенциальных обработчиков и последующая регистрация этих обработчиков для ошибки «Недостаточно памяти» не имеет большого смысла; это было бы примером использования модели наблюдателя в этой ситуации. Во время выполнения вы можете захотеть изменить то, какие методы вызываются или какой «делегат» вызывается для переменных событий, но выгрузка обработчика события для определенного события во время выполнения не является нормальной.

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.