События и ухудшение навигации
Что же делать, если вся задача именно в обработке событий (часто внешних)?
Что же делать, если вся задача именно в обработке событий (часто внешних)?Что такое внешние события? События у классов из сторонней библиотеки, сорци которой вы не можете править? Если так, то вопрос о выборе решения не стоит, у вас просто нет выбора.
Понятно, что события включают в себя полиморфизм, поэтому код лучше расширяется, но расширение может не понадобиться, а мы уже за него заплатили ухудшением навигации.как бы тут вроде тема и раскрывается: динамический полиморфизм
а события и изменяемое состояние упомянуты лишь что бы запутать читателя имхо
События от внешних устройств, клавиатура там, мышь, еще что-нибудь... И нет никаких внешних библиотек, все надо писать самому.
События от внешних устройств, клавиатура там, мышь, еще что-нибудь... И нет никаких внешних библиотек, все надо писать самому.Если весь код полностью твой, то не обязательно делать события у своих классов/типов.
Если весь код полностью твой, то не обязательно делать события у своих классов/типов.Ну, так вопрос как раз в том "как делать".
Спрятать голову с песок, вынеся событийность из классов/типов и делать вид, что их (событий) у нас нет?
как бы тут вроде тема и раскрывается: динамический полиморфизмСитуация аналогичная вот этой:
а события и изменяемое состояние упомянуты лишь что бы запутать читателя имхо
class A1
{
public void M1
{
Console.WriteLine(P1);
}
public string P1 { get; set; }
}
class A2
{
private readonly string p1;
public A2(string p1)
{
this.p1 = p1;
}
public void M1
{
Console.WriteLine(p1);
}
}
Для A2 навигация Value Origin легко находит значения P1. Для A1 придется отслеживать controll flow от создания экземпляра до вызова метода M1.
Ну, так вопрос как раз в том "как делать".Реализовывать требуемый алгоритм. Если в самом алгоритме нет динамичности (а такое часто бывает то и события (на классах или объектах) не нужны.
Спрятать голову с песок, вынеся событийность из классов/типов и делать вид, что их (событий) у нас нет?
Событие от мышки не есть событие на объекте. Тут у слова "событие" две различные семантики.
Для любителей динамических языков эта проблема малозаметна (поскольку там с навигацией итак плохо но для тех, кто использует преимущества статической типизации, это весьма существенный вопрос.Я согласен. Но как эта тема будет reducto ad controllable query?
Событие от мышки не есть событие на объекте. Тут у слова "событие" две различные семантики.Так ты можешь объяснить словами свою семантику?
Так ты можешь объяснить словами свою семантику?Совсем грубо семантика события на объекте выглядит так: у объекта есть поле-коллекция, в которую можно добавлять/удалять колбеки. Более точно и детально смотри спецификацию своего языка.
Ага. То есть вся тема о том, что указатели сильно могут запутать код, а указатели на функции сделают это в два раза быстрее. Спасибо Кэп.
Ага. То есть вся тема о том, что указатели сильно могут запутать код, а указатели на функции сделают это в два раза быстрее. Спасибо Кэп.Вышесказанное относится и к языкам, в которых нет явных указателей.
Ага. То есть вся тема о том, что указатели сильно могут запутать код, а указатели на функции сделают это в два раза быстрее. Спасибо Кэп.Это намекает на то, что у тебя ООП головного мозга. У тебя либо РЕАЛЬНЫЕ объекты, либо низкоуровневые указатели, так?
От фразы "объекты, которые отражают наш реальный мир" меня начинает подташнивать.
>> а указатели на функции сделают это в два раза быстрее. Спасибо Кэп.
> Это намекает на то, что у тебя ООП головного мозга.
Это намекает на то, что у тебя IDE головного мозга.
(Между прочим, первый и второй примеры у тебя заведомо неравнозначны,
поэтому сравнивать их просто так --- бессмысленно.)
---
"Университет развивает все способности, в том числе и глупость."
Это намекает на то, что у тебя IDE головного мозга.
IDE по крайней мере из реального мира, а не из бредней
сравнивать их просто такпросто так их никто и не сравнивает
ты пост прочитал?
ООП тоже из реального мира.
>> сравнивать их просто так
> просто так их никто и не сравнивает
> ты пост прочитал?
Да. Ты написал два кривых примера, которые неравнозначны,
а потом сравнил их по произвольно взятому малоосмысленному признаку.
Более того, потом и ещё бреда добавил, как будто мало было.
---
"Университет развивает все способности, в том числе и глупость."
ООП тоже из реального мира.Его увидеть можно? IDE можно.
А как же cohesion/coupling? События помогают развязать объекты, снять зависимости. Навигация страдает, конечно.
События помогают развязать объекты, снять зависимости.Помогают, но в C# control flow становится такой кашей, что лучше развязывать не через события.
просто тоже тут над одним местом думаю. Тут плюсы, но я сделал подписывание. Но терзают смутные сомнения. Раньше было жестко зашито, код трудно понимался.
Но терзают смутные сомнения.Ты ещё сомневаешься? Смесь event driven с изменяемым состоянием и без корутин - самый адский вариант, который только можно придумать в области разработки ПО.
Раньше было жестко зашито, код трудно понимался.Мне вообще не ясно, как будет пониматься большой объём кода, в котором много неявных вызовов.
Возможно. Надо видимо вообще какой-то отдельный класс, отвечающий за состояние выделить. А то когда кучка объектов должна синхронно изменять состояние, начинает поднадоедать.
Надо видимо вообще какой-то отдельный класс, отвечающий за состояние выделить. А то когда кучка объектов должна синхронно изменять состояние, начинает поднадоедать.Я не понял, о чём ты хотел сказать, и как это связать с событиями.
Есть кучка объектов, которые слабо связаны между собой, через простые интерфейсы. Но они должны менять состояние одновременно. Раньше этих тонких интерфейсов вообще не было, все были повязаны. Я развязал, но вот эту часть, которая отвечает за смену состояния, сделал через событие. Надо видимо сделать по-другому.
Но они должны менять состояние одновременно.Главный вопрос в том, как это происходит. Если смена состояния происходит последовательно, то проблем обычно не возникает. Если хаотично, когда разные объекты могут менять одни и те же данные в любом порядке, и их поведение зависит от этих данных, то проблемы будут в любом случае. Даже в stateless архитектуре. В этом случае лучше явно выстраивать объекты в очередь для выполнения изменений.
Я развязал, но вот эту часть, которая отвечает за смену состояния, сделал через событие.Когда возникнет ошибка, ты просто заебёшься выяснять, какие условия к ней привели.
Когда возникнет ошибка, ты просто заебёшься выяснять, какие условия к ней привели.Ну логика тут довольно железная, причем код основной, работает всегда. Тут баг легко будет отловить. Но от событий попробую избавиться.
И все они должны при этом понять, что что-то изменилось (и еще получить какой-то контекст этого нового состояния).Они что-нибудь делают по факту смены состояния или нет?
Ну если бы не делали, я бы этого не городил Но там мало действий, они все связаны именно с осознанием смены состояния.
Ну если бы не делали, я бы этого не городил Но там мало действий, они все связаны именно с осознанием смены состояния.А почему нельзя явно сделать что-то типа foreach ... some_interface->state_changed без события?
Т.е. сейчас
B->NotifyMe(A)
C->NotifyMe(B)
D->NotifyMe(B)
А ты предлагаешь
B->NotifyMe(A)
C->NotifyMe(A)
D->NotifyMe(A)
Хотя так не выйдет, ибо C и D много, как я говорил. Каждый из них приписан одному B, а все B к одному A.
Видимо просто реально сделаю это отдельным классом для смены состояния.
Хотя так не выйдет, ибо C и D много, как я говорил. Каждый из них приписан одному B, а все B к одному A.Я опять не до конца понял, что ты делаешь. Как я понял, твои объекты ссылаются друг на друга, зачем здесь события, если родители могут уведомлять потомков, реализуя Composite.
Т.е. есть Composite. Все равно по коду сложнее понять, кто конкретно будет уведомлен в итоге по сравнению с прямым вызовом.
Те, кому надо, подписываются (= добавляются узлами Composite).Такое реверсивное поведение только усложняет логику программы. Добавлять должен либо родитель, либо третье лицо. Лучше избегать ситуаций, когда дочерний объект добавляется в родителя.
Т.е. есть Composite. Все равно по коду сложнее понять, кто конкретно будет уведомлен в итоге по сравнению с прямым вызовом.Интерфейсы - это дешёвая с точки зрения поддержки и читаемости вещь. Поэтому можно сделать иерархию с разными методами.
Такое реверсивное поведение только усложняет логику программы. Добавлять должен либо родитель, либо третье лицо. Лучше избегать ситуаций, когда дочерний объект добавляется в родителя.Но родитель не может добавить, потому что не хочет знать о конкретных детях, его конфигурирует "кто-то другой". Так вот этот кто-то другой теперь должен при добавлении этих детей еще и не забывать их подписать? Что-то сложно поверить. Т.е. мне кажется, это не лучше, чем если дети самоподписываются. Лучше — по-другому сделать вообще.
Так вот этот кто-то другой теперь должен при добавлении этих детей еще и не забывать их подписать?При чём тут подписывание, у родителя же есть список детей, который наполняется "этим кем-то". Из этого сразу же получается Composite. Здесь не нужно никакого отдельного "подписывания".
Но родитель не может добавить, потому что не хочет знать о конкретных детях, его конфигурирует "кто-то другой". Так вот этот кто-то другой теперь должен при добавлении этих детей еще и не забывать их подписать? Что-то сложно поверить. Т.е. мне кажется, это не лучше, чем если дети самоподписываются. Лучше — по-другому сделать вообще.Напиши код, условно говоря в одном методе. Где есть ветвление вводишь полиморфизм (возможно несколько раз). Потом раскидаешь с помощью IDE код по нужным типам. Код сам тебе подскажет правильную структуру, поскольку в коде уже есть все связи. А так, ты пытаешься все связи проворачивать в голове. Это как решать систему уравнений в голове, хотя на бумаге она решается тривиально.
Оставить комментарий
6yrop
Использование событий ухудшает навигацию по коду. В общем-то, это почти тривиальный факт. И он является частным случаем того факта, что навигация ухудшается при использовании изменяемого состояния. События это изменяемый массив колбеков, т.е. изменяемое состояние. Тем не менее, хочу привести код, на котором явно видно ухудшение навигации.Код с событием:
Код без события:
В первом варианте нам надо самим проследить controll flow от создания экземпляра класса A до вызова метода a.M1 и найти в этом flow подписку на событие. Controll flow может быть довольно сложным.
Во втором варианте современная IDE показывает тело метода A.M1:
Понятно, что события включают в себя полиморфизм, поэтому код лучше расширяется, но расширение может не понадобиться, а мы уже за него заплатили ухудшением навигации. При том полиморфизм можно будет ввести в будущем и необязательно через событие.
Для любителей динамических языков эта проблема малозаметна (поскольку там с навигацией итак плохо но для тех, кто использует преимущества статической типизации, это весьма существенный вопрос.