Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.71/7: Рейтинг темы: голосов - 7, средняя оценка - 4.71
Заблокирован

Чем паттерн Наблюдатель лучше механизма событий?

19.10.2023, 11:31. Показов 2237. Ответов 34
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
На первый взгляд, паттерн Наблюдатель легко заменяется, даже код проще будет и понятнее, с помощью событий. Если это не так, то почему не так?
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
19.10.2023, 11:31
Ответы с готовыми решениями:

Паттерн наблюдатель
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Observer { class...

Делегат (Паттерн наблюдатель)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace...

Создать паттерн Наблюдатель
У меня есть клас BALANS в нем есть 2 списка List<POSTAVKA_TOVARU> obj2 = new List<POSTAVKA_TOVARU>(); List<PRODAZH_TOVARU> obj3 =...

34
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
19.10.2023, 22:26
Студворк — интернет-сервис помощи студентам
titan4ik, так делегаты и события предоставляют это все. С, уже (на минуточку), реализованным Наблюдателем...
От сюда вопрос - "с какой целью интересуетесь"?
1
 Аватар для IamRain
4694 / 2702 / 734
Регистрация: 02.08.2011
Сообщений: 7,236
19.10.2023, 22:40
Лучший ответ Сообщение было отмечено titan4ik как решение

Решение

Цитата Сообщение от titan4ik Посмотреть сообщение
То есть, нет никакого смысла его использовать в c# в своем оригинальном виде - без событий?
Если нет никаких особых требований к реализации паттерна, то нет. Например, при множестве обработчиков, эти обработчики выполняются последовательно, друг за другом. Устраивает? - оставляйте.
Если нужен просто мгновенный сигнал на большое число подписчиков, то велосипедим свое, пример сравнения:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//нужно понимать как правильно реализовывать async обработчики, чтобы они отпускали вызывающий поток быстро
//возможно придется велосипедить свой базовый функционал, чтобы облегчить написание
using System.Diagnostics;
 
var bar = new Bar();
bar.ActionCompleted += OnCompleted1;
bar.ActionCompleted += OnCompleted2;
bar.ActionCompleted += OnCompleted3;
bar.AsyncCompleted += OnAsyncCompleted1;
bar.AsyncCompleted += OnAsyncCompleted2;
bar.AsyncCompleted += OnAsyncCompleted3;
 
 
var now = Stopwatch.GetTimestamp();
bar.OnActionCompleted();
var timestamp = Stopwatch.GetElapsedTime(now);
Console.WriteLine($"Elapsed: {timestamp}");
 
now = Stopwatch.GetTimestamp();
bar.OnAsyncActionCompleted();
timestamp = Stopwatch.GetElapsedTime(now);
Console.WriteLine($"Elapsed: (async) {timestamp}");
 
static void OnCompleted1()
{
   Thread.Sleep(500);
}
 
static void OnCompleted2()
{
   Thread.Sleep(500);
}
 
static void OnCompleted3()
{
   Thread.Sleep(500);
}
 
static async Task OnAsyncCompleted1()
{
   await Task.Delay(500);
}
 
static async Task OnAsyncCompleted2()
{
   await Task.Delay(500);
   Thread.Sleep(500);
}
 
static async Task OnAsyncCompleted3()
{
   await Task.Delay(500);
}
 
;
 
class Bar
{
   public event AsyncEventHandler AsyncCompleted;
   
   public Action ActionCompleted;
 
   public void OnActionCompleted()
   {
      ActionCompleted?.Invoke();
   }
   
   public void OnAsyncActionCompleted()
   {
      AsyncCompleted?.Invoke();
   }
}
 
internal delegate Task AsyncEventHandler();
Цитата Сообщение от titan4ik Посмотреть сообщение
Не какие-то там типы ObservableCollection<T> и т.п., а именно паттерн?
А что для вас значит "именно паттерн"?
Многие вещи нужно прочувствовать через практику, чтобы понять как это работает.
Если вам напишут в статье "ExecutionContext is everywhere where code is executed." - Вы поймете? Как создать кастомный ExecutionContext?
У вас не было никогда ощущения, что вы является коробочным (out-of-box) непрограммистом? Вот есть WCF, настроил binding-и и вуаля - можно пользоваться. Но кто-то же это написал.
Тут еще можно провести аналогию паттернов как со стандартами/протоколами и их реализациями.
Блин, слишком много тут вам придется расписывать, чтобы дать исчерпывающий ответ. Мне лень это делать в 3-ем часу ночи...
Слишком много может быть нюансов, поэтому нужно все пропускать через себя.
1
Заблокирован
19.10.2023, 23:03  [ТС]
Цитата Сообщение от IamRain Посмотреть сообщение
У вас не было никогда ощущения, что вы является коробочным (out-of-box) непрограммистом?
Я скорее - антикоробочный непрограммист) Меня как раз в современном программировании напрягает обилие библиотечных разных ништяков и т.п.. У меня в программировании был перерыв в 40 лет) Тогда, в начале 80-х годов всё было "немного не так") Написал программку на фортране, девочка в белом халатике набила её на перфокарты или перфоленту и потом другой девочке отдаёшь всё это и через час или сутки получаешь распечатку с какой-нибудь фигнёй. Ищешь и исправляешь ошибку и опять...) А если нужно оптимизировать процесс вычислений, то с перфокартами отдаёшь девочке шоколадку. Так ЭВМ гораздо быстрее считала. И тогда можно было больше "прогонов" сделать за сутки) Эх!
Цитата Сообщение от IamRain Посмотреть сообщение
Если нет никаких особых требований к реализации паттерна, то нет. Например, при множестве обработчиков, эти обработчики выполняются последовательно, друг за другом. Устраивает? - оставляйте.
Если нужен просто мгновенный сигнал на большое число подписчиков, то велосипедим свое, пример сравнения:
IamRain, ну, и тут Вы обошлись языковыми средствами - событиями. То есть, нет смысла делать велосипед без событий. ОК.
Спасибо!

Добавлено через 5 минут
Цитата Сообщение от wizard41 Посмотреть сообщение
так делегаты и события предоставляют это все. С, уже (на минуточку), реализованным Наблюдателем...
От сюда вопрос - "с какой целью интересуетесь"?
Хотел уточнить. Окончательно прояснить. Расставить все точки над и. Там выше же объяснял. Не обижайтесь на дурака)
0
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
19.10.2023, 23:07
Цитата Сообщение от titan4ik Посмотреть сообщение
Окончательно прояснить
Так проясни! Хочешь разобраться в вопросе - реализуй сам. Не хочешь - юзай события.
Все!
0
Заблокирован
19.10.2023, 23:09  [ТС]
Цитата Сообщение от IamRain Посмотреть сообщение
А что для вас значит "именно паттерн"?
В данном контексте - паттерн - это шаблон решения типовой задачи.

Добавлено через 1 минуту
Цитата Сообщение от wizard41 Посмотреть сообщение
Так проясни! Хочешь разобраться в вопросе - реализуй сам.
Да с работой самого паттерна всё понятно было изначально.
ВСЁ!)
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
20.10.2023, 09:00
Лучший ответ Сообщение было отмечено titan4ik как решение

Решение

Цитата Сообщение от titan4ik Посмотреть сообщение
То есть, нет никакого смысла его использовать в c# в своем оригинальном виде - без событий?
События — это просто дефолтная реализация, предоставляемая "из коробки". Пользоваться ей или написать свою — это ваше дело, зависеть будет от конкретных требований.
Если вам нужен какой-то дополнительный функционал, как например тот, который предоставляется интерфейсом IObserver, то реализуйте с нуля на здоровье.
Так же стоит учитывать, что события были в языке с версии 1.0, т.е. этой реализации уже без малого 25 лет. За годы язык оброс дополнительным функционалом и подходы к реализации несколько поменялись — в некоторых случаях функционал событий может быть не достаточным для вашего сценария.
Например, подписчики в событиях выполняются последовательно. Если вам нужна параллельная обработка, то события не подходят.
Так же события/мультикаст-делегаты практически не работают с асинхронными методами.
Или у вас какой-то расширенный функционал, требующий дополнительного взаимодействия с подписчиками, который отсутствует в делегатах (см. тот же IObserver).

В общем, смотрите по ситуации. Если события решают вашу задачу — пользуйтесь на здоровье.
1
 Аватар для Midian
608 / 390 / 198
Регистрация: 31.03.2013
Сообщений: 2,700
20.10.2023, 09:12
Цитата Сообщение от IamRain Посмотреть сообщение
public event AsyncEventHandler AsyncCompleted;
public Action ActionCompleted;
C#
1
public event Action ActionCompleted;
1
 Аватар для IamRain
4694 / 2702 / 734
Регистрация: 02.08.2011
Сообщений: 7,236
20.10.2023, 09:23
Midian, да не суть, поведение не изменится.
Цель того примера - показать, что 3 синхронных подписчика займут 1.5 секунды времени (каждый проспав по 0.5), а асинхронные подписчики тоже будут выполняться последовательно, но они не будут выполнять код, а просто стартовать Task-и на потоках из пула.
Это может быть важно, когда например, объект - Observable - выполняющий какой-то hot-throughput path код (например, в сетевых приложениях), должен очень быстро выполнять уведомление своих подписчиков и быстро продолжать свою работу. То есть это яркий пример, когда может понадобиться offloading (тот что дает нам responsiveness в GUI приложениях).
Хотя для сигналов у Task-ов еcть более надежные механизмы - TaskCompletionSource-ы, или всякие ванильные *ResetEvent-ы. Но это уже другая история.
1
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
20.10.2023, 09:46
Технически event -- так называемый "сахар", который призван упростить написание однотипного кода. Грубо говоря нам очень часто нужно для объекта по изменению его состояния сделать какие-либо действия. Самая простая реализация выглядит так:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class MyObject
{
 
List<Action<MyObject>> handlers = new();
 
public void Subscribe(Action<MyObject> handler)
    => handlers.Add(handler);
 
protected virtual void OnChange() => 
{ 
    /* change object  */ 
    foreach(var action in handlers)
        action(this);
}
 
}
Ну и Unsubscribe, для удаления. Не учитывается многопоточность, список нужно делать readonly и т.д. Так вот, чтобы каждый раз не копипастить один и тот же кусок -- придумали event. Причем event, на равне с свойствами get|set, -- тупо методы add|remove, которые принимают делегаты. Т.е. мы всегда можем проигнорировать дефолтную реализацию, и наваять свою (например для того чтобы обработка запускалась в многопотоке, и/или ошибки на прерывали выполнение других обработчиков).

Теперь насчет IObserver и прочего.

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

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

Третье:
Цитата Сообщение от kolorotur Посмотреть сообщение
Так же события/мультикаст-делегаты практически не работают с асинхронными методами.
Если ещё больше обобщить -- если ваш обработчик какого-то фига должен возвращать значение -- event тут ну ооочень не очень.
1
Заблокирован
20.10.2023, 12:19  [ТС]
Цитата Сообщение от kolorotur Посмотреть сообщение
События — это просто дефолтная реализация, предоставляемая "из коробки". Пользоваться ей или написать свою — это ваше дело, зависеть будет от конкретных требований.
Цитата Сообщение от Wolfdp Посмотреть сообщение
Технически event -- так называемый "сахар", который призван упростить написание однотипного кода.
Это всё понятно. Конечно - события это удобный инструмент. Конечно - пользоваться. Тут даже вопросов нет.
Цитата Сообщение от kolorotur Посмотреть сообщение
подписчики в событиях выполняются последовательно. Если вам нужна параллельная обработка, то события не подходят.
Так же события/мультикаст-делегаты практически не работают с асинхронными методами.
Не понимаю проблемы.
Что касается возможности параллельного выполнения делегатов - мне это отличие явной реализации паттерна Наблюдатель от событий сразу в глаза бросилось. Но я решил, что асинхронные методы, подписанные на событие, запускаемые последовательно и выполняемые асинхронно (могут и параллельно выполняться - это уже решит мудрая автоматическая оптимизация) решают проблему. В каком случае это не так?
Добавлено через 9 минут
Цитата Сообщение от Wolfdp Посмотреть сообщение
если ваш обработчик какого-то фига должен возвращать значение -- event тут ну ооочень не очень.
И тут проблемы особой не вижу. Событие "произошло" - запустились методы-обработчики (получив какие-то данные от события)и изменили какие-то свойства какого-то объекта (так и передали данные дальше).

Добавлено через 6 минут
Цитата Сообщение от kolorotur Посмотреть сообщение
Или у вас какой-то расширенный функционал, требующий дополнительного взаимодействия с подписчиками, который отсутствует в делегатах (см. тот же IObserver).
А это наверное про что-то очень сложное. Приму к сведению, хоть и не понимаю о чем. Делегаты запускают соответствующие методы. Казалось бы методами можно любой функционал реализовать.
0
 Аватар для Midian
608 / 390 / 198
Регистрация: 31.03.2013
Сообщений: 2,700
20.10.2023, 12:26
Цитата Сообщение от IamRain Посмотреть сообщение
да не суть, поведение не изменится.
Я к тому, что не нужно писать лишние 3 строки:
C#
1
2
3
public event AsyncEventHandler AsyncCompleted;
public Action ActionCompleted;
internal delegate Task AsyncEventHandler();
Все заменяется 1 строчкой, которую удобнее читать и вызывать:
C#
1
2
public event Action ActionCompleted;
ActionCompleted?.Invoke();
Добавлено через 5 минут
Цитата Сообщение от IamRain Посмотреть сообщение
Цель того примера - показать, что 3 синхронных подписчика займут 1.5 секунды времени (каждый проспав по 0.5), а асинхронные подписчики тоже будут выполняться последовательно, но они не будут выполнять код, а просто стартовать Task-и на потоках из пула.
Ну подпишитесь на это событие и в подписке стартуйте в методе в своей таске некий код, получится тоже самое в любом случае, событие выполняется в главном потоке в очереди Dispatcher и при подписке в определенном порядке он будет вызвано тоже в этом же порядке
1
Заблокирован
20.10.2023, 12:32  [ТС]
В общем, по сути вопроса ответ получен. Его можно так резюмировать:
Если механизм событий удовлетворяет, то паттерн Наблюдатель нет смысла явно реализовывать. А если по каким-то критериям механизм событий не решает задачи или решает не лучшим образом, то тогда можно решать её через явную реализацию паттерна, используя все его возможности (это надо ещё понять что там за особые возможности - простые примеры реализации их не раскрывают) и дополнительно включая туда всё необходимое. Понятно. Это понятно. Спасибо!
Попутно в обсуждении было много интересного (и не вполне понятного - спасибо, есть что иметь ввиду для дальнейшего понимания!).
0
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
20.10.2023, 12:38
Цитата Сообщение от titan4ik Посмотреть сообщение
И тут проблемы особой не вижу.
проблема в том, что агрегированый делегат вернет только последний результат. А вот понять какой результат был последний, или что до него -- нельзя

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
var neko = new Neko();
 
Task.WaitAll(
    Task.Run(async () =>
    {
        await Task.Delay(Random.Shared.Next(100, 200));
        neko.Nya += () => true;
    }),
    Task.Run(async () =>
    {
        await Task.Delay(Random.Shared.Next(100, 200));
        neko.Nya += () => false;
    })
);
 
neko.Pet();
 
Console.ReadKey();
 
class Neko
{
    public event Func<bool>? Nya;
 
    public void Pet()
    {
        var result = Nya?.Invoke();
 
        Console.WriteLine(result);
    }
}
У нас неизвестная очередность подписки, и из-за этого разный результат. И это не вспоминая что слушателей вообще может не быть (но это мелочи).

Теперь насчет асинхроных методов. По сути это Func<Task> для примера выше, и в коде вместо Console.WriteLine(result); нужно выполнить await для всех подписантов (ну или около того). Но как писал выше -- мы можем получить только последний результат (который ещё и не гарантирован средой CLR, т.е. на одной версии очередность будет одна, на другой -- иная).
2
Заблокирован
20.10.2023, 12:48  [ТС]
Цитата Сообщение от Wolfdp Посмотреть сообщение
У нас неизвестная очередность подписки, и из-за этого разный результат. И это не вспоминая что слушателей вообще может не быть (но это мелочи).
А..., в этом смысле. Понятно.

Добавлено через 2 минуты
Wolfdp, спасибо за разъяснения!
0
Заблокирован
28.02.2024, 18:22  [ТС]
Добавлю статейку по теме: https://www.codeproject.com/Ar... -in-Csharp
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
28.02.2024, 18:22

Паттерн Наблюдатель - записать содержимое TextBox в файл
Пытаюсь разобраться с сутью паттерна &quot;Наблюдатель&quot; . Необходимо, чтобы при изменениях в textbox он отправлял всё его содержимое в файл. ...

Паттерн Наблюдатель
Реализуйте поведенческий паттерн проектирования &quot;наблюдатель&quot; (Observer) для работы персонала ресторана (консольное дополнение). Помогите с...

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

паттерн Наблюдатель и логгирование
Задавал этот вопрос в соседней теме, но никто не ответил, потому создам новую :) Я делаю веб-приложение, в котором логгирование...

Паттерн наблюдатель vs События
Добрый день. Подскажите пожалуйста, что правильнее использовать при программировании на C#: паттерны наблюдатель или механизм событий? ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
35
Ответ Создать тему
Новые блоги и статьи
Нейтральные знания, чистый код - бла-бла-бла-бла, на самом деле кликбейт и самореклама, плагиат, и вот почему
Hrethgir 27.07.2026
То-есть отклонение такой публикации говорит само за себя, и пусть только возьмут на вооружение после отклонения публикации - это будет чистейшим актом плагиата. Отклонял Хабр. Дословно, отклонённая. . .
тв 16 бой ии
anaschu 27.07.2026
Великий Перелом ИИ: Как уравнения ОДУ Radau дожали цензурные фильтры Алисы Фиксируем в мемофонде Теории Всего беспрецедентный факт в истории ИИ-зондирования. В затяжном многораундовом. . .
мв 15. непроверенное, возможно, глюк
anaschu 27.07.2026
НАУЧНО-АНАЛИТИЧЕСКИЙ ОТЧЕТ. РАЗДЕЛ 1. 1: «НАУКА» (РАСШИРЕННАЯ СТЕХИОМЕТРИЧЕСКАЯ И ГЕНЕТИЧЕСКАЯ ВЕРСИЯ)Тема: Теоретическое обоснование инвариантности 19-мерного тензорного ядра непрерывных ОДУ и. . .
Очистка реквизитов и табличных частей документа при копировании (вариант 2)
Maks 26.07.2026
Алгоритм из решения ниже разработан на примере нетипового документа "ЗаявкаНаРаботу", разработанного в КА2. Задача: Заменить алгоритм запрета копирования документов для сотрудников с ролью "Стажер",. . .
Доктрина интенционального знания - Доктрина для портала "Срез".
Hrethgir 25.07.2026
Может найдётся кто захочет оценить доктрину. . . Написания правил участия для меня роскошь, требующая лимита времени, поэтому все сообщения не прошедшие модерацию будут видны только участникам портала,. . .
сукцессия 44. Решил подать на припринт в межународные сервисы препринтов. Но нужно одобрение от ученых
anaschu 25.07.2026
Английский вариант. Пока кто то не одобрит мою личность, мне не получиться это опубликовать на препринте. Но заявку на публикацию статьи я сегодня подам.
сукцессия 43. Вторая научная статья за месяц- прайминг и гатгил
anaschu 25.07.2026
две стороны одной монеты
Более приземисто - Эстафету хвоста в .cdl (деревья эстафеты в сад).
Hrethgir 24.07.2026
В будущем, после написания блока инверсии обхода дерева (эстафеты хвоста), я планирую вернуться к нашему прошлому разговору о том, обладают ли знания целеполаганием. Тогда я пришел к выводу, что. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru