00:08
@tym32167 спасибо за терпение и что продолжаете отвечать) Я не просто поспорить или поумничать пришел, мне действительно хочется понять как же все-таки правильно. По поводу D из SOLID. Событийная модель - это и есть абстракция, и подписка логики на события интерфейса это механизм как раз слабого, а не сильного связывания. UI генерирует события, а логика реагирует на те, которые ее интересуют, то есть инициатива остается за ней.
00:20
@tym32167 А вот вызов обработчиком события логики это уже конкретика, явно прописанная в самом UI, и подлежащая изменению каждый раз, когда эта логика будет изменена (удаление метода, к примеру). По поводу примера с консолью. Событийная модель может прекрасно работать и в консоли. Весь вопрос в том, что там будет генерировать эти события, а не в том, как их обрабатывать.
@tym32167 Ваш пример в этом плане не лучше - событие вызывает обработчик, он вызывает логику. А как вызывать нужную логику в консоли? Допустим, переделаем обработчик в самостоятельный метод, который будет вызывать остальную логику (так ведь должно быть если сменить UI на консоль?). Опять получается, что все все про всех знают, и опять получается сильная связность. С событиями этого просто не может произойти - нужно, например, удалить обработчик - удаляем вместе с подпиской на событие.
00:41
@tym32167 каким образом реакция на новое событие и его упоминание в логике ломают S и O? Святым духом инфа от кнопок не передается - кто-то где-то должен быть упомянут. Разница в том, что событийная модель это абстрация, а перечисление и вызов всех нужных методов из логики - конкретика. Мы хотим в каком-то классе реагировать на событие - мы подписываемся на него. Понадобилось вообще удалить класс с обработчиком - ничего не сломается. Слабее связности не придумаешь, как по мне.
01:33
@JamesBond всё проще. Вы упоминаете событийную модель, но что это конкретно значит? Что у окна, то есть представления, есть свои события. Всё. Каждый класс, который подписывается на эти события, должен о них знать. А значит, этот класс без окна смысла не имеет, ник просто нужно окно, чтобы работать. Это сильная связность.
Если же мы говорим об абстрактных событиях системы передающимся через общую шину сообщений - вот это событийная модель для слабого связывания, при этом окно со своими событиями не имеет с этой моделью ничего общего. В такой модели все события связаны с системой, условно, там есть событие "создан новый заказ", но нет события "юзер нажал зеленую кнопку".
Как это связано с консолью? Вот мы говорим про калькулятор. Там должен быть класс, что рассчитывает выражение и возаращает результат. Следуюя S и SOLID, этот класс должен заниматься только расчетами, больше ничем. Никаких подписок никуда ему не надо, чтобы вычислить выражение. Потому, если будет консоль, то у консоли будут свои обработчики консольных команд, которые вызовут этот класс для нужныжх расчетов. То есть в случае консоли никаких событий не надо вовсе.
При этом не путайте событие уровня приложения (та самая событийная модель) и события окна - это разные события, они создаются по разному, их назначение разное, у них разные подписчики, всё разное.
"UI генерирует события, а логика реагирует на те, которые ее интересуют, то есть инициатива остается" - логике вообще должно быть всё равно, что там в UI происходит. Еще раз, есть слой выше и ниже в приложении. UI - это верхний слой, логига приложения - это слой ниже. Верхний слой должен вызывать нижний, а не наоборот. Верхний слой должен знать о нижнем, нижний о верхнем знать не должен
это как пирамида, сверзу у вас UI , пол ним у вас какая то логика, под логикой у вас более низкоуровневые вещи типа доступа к БД или вызовов по сети или что еще. Процесс инициированный сверху юзером должен идти вниз, а не наоборот
по поводу связности, да, вы можете разделить слои или части вашего приложения используя общую шину сообщений (это не про события окна!). Такой пример действительно есть и это довольно продвинутые вещи, которые я вам бы не советовал трогать пока не освоитесь с более простыми вещами
для закрепления, если вашей логике нужно окно, чтобы подписаться на его события - у вас проблема связи логики с окном, логика начинает знать кто и как её вызывает, ничем хорошим это не заканчивается. Держитесь простого принципа что слои верхнего уровня вызывают слои нижнего уровня, а не наоборот, и вы уже избежите множества проблем с кодом
"А вот вызов обработчиком события логики это уже конкретика, явно прописанная в самом UI, и подлежащая изменению каждый раз, когда эта логика будет изменена (удаление метода, к примеру)." - нет, не так. Если логика меняется, она меняется внутри методов логики. Единственной причиной лезть в обработчике будет только если вызов какой то логики вообще больше не нужен, что бывает не так часто.
3 hours later…
06:14
@tym32167 ну, технически, это мы знаем что в данном случае у нас события UI. Для логики же это не события UI, а "какие-то события", которые точно также могут легко быть воспроизведены в консоли, просто там это будет уже не "событие Click из WimForms", а "событие Click самого приложения". Но в целом уже начинаю сомневаться - если на консольку перейти легко, то вот сменить, например, WinForms на WPF уже нет. Надо обдумать все как следует...
06:36
Вообще, пример того же калькулятора наводит на слудующие соображения. Есть поле для ввода, которое само по себе не создает интересных событий, и кнопка "=", инициирующая передачу выражения в логику. Кнопка может вызвать логику, но не может передать дополнительные данные - отсутствует EventArgs. Значит, нужно создавать свое событие, у которого EventArgs будет, и которое будет вызываться при нажатии на кнопку, а оно само в свою очередь уже будет вызывать логику.
06:52
По поводу S и смены логики - я на это и делал упор большую часть времени. Если логика меняется (или стала не нужна), то в модели где логика сама подписывается на интересующие события это не вызовет проблем и не потребует изменений больше нигде кроме класса логики (просто отписались от события и всё). UI менять не потребуется. В общем, я запутался, надо еще раз все обдумать)
8 hours later…
14:56
@JamesBond если это другие события - то и реакция на них другая, и процесс подписки другой, и данные что приезжают с событием другие - соответвенно класс который подписывается подлежит ищменениям, что и означает сильную связность. Если у вас было событие "юзер нажал на синюю кнопку", а стало событие "юзер ввел что то в консоль" - то сами обработчики таких событий совершенно другие.
@JamesBond вы патаетесь решить проблемы UI слоя новой абстракцией. Это только усложняет код и не привиодит ни к чему хорошему. В примере калькулятора, есть UI слой со своими обработчиками своих событий и есть логика калькулятора. Калькулятору должно быть все равно, кто его вызывает. UI слой может в своих обработчиках вызвать калькулятор тогда, когда посчитает нужным
@JamesBond вам андо понять, что подписка на UI события и обработка этих событий - это логика UI, это не бизнес логика, это чисто лоника UI слоя. Потому если если надо изменить код обработчтика нажатия зеленой кнопки - это изменение UI слоя, это не изменение бизнес логики. В случае калькулятора - вычисление выражения, - это бизнес логика, а запись результата этого вычисления в поле на форме - это UI логика. Они мало связаны между собой.
15:58
@tym32167 Возможно, меня все это время сбивало то, что я пытался думать в контексте паттерна MVC (который пока плохо понимаю). Нашел вот такую информацию:
О чем знают модель, представление и контроллер?
1. Модель не знает о существовании представления и контроллера;
2. Представление знает о модели, но не знает о контроллере.
3. Контроллер знает и о модели, и о представлении.
Контроллер не всегда является отдельным классом, часто частью представления на основе GUI в M/VC.
О чем знают модель, представление и контроллер?
1. Модель не знает о существовании представления и контроллера;
2. Представление знает о модели, но не знает о контроллере.
3. Контроллер знает и о модели, и о представлении.
Контроллер не всегда является отдельным классом, часто частью представления на основе GUI в M/VC.
2 hours later…
18:41
@tym32167 спасибо за уделенное время и подробные ответы) Я сейчас понял, в чем еще была моя проблема. Я отталкивался от паттерна MVC, но при этом интуитивно у меня было ощущение, что первой в иерархии структуры приложения должна идти вьюшка. Отсюда возникла ассоциация, что окно - это M в MVC)) Поэтому я подсознательно их отождествлял и все время старался сделать вьюшку независимой. Теперь понятно, в чем была ошибка.
18:54
Ну и еще я сильно переоценил нейросети - в паттернах они плавают еще почище, чем я сам) Так что сейчас нужно найти хорошие, понятные описания MVC, MVP и Document-View (для чего-то мелкого), и разобраться с ними.
По правде еще, львиная доля всей путаницы возникла из-за WinForms и partial-класса Form. Если полностью описывать все кодом, вся программа легчайше делится на любые части и по любому паттерну. Но это долго учить(
По правде еще, львиная доля всей путаницы возникла из-за WinForms и partial-класса Form. Если полностью описывать все кодом, вся программа легчайше делится на любые части и по любому паттерну. Но это долго учить(
« first day last day (15 days later) »
Transcript for
Sep13
Sep14
Sep29
Discussion on question by James Bond:…
Imported from a comment discussion on ru.stackoverflow.com/que...