last day (16 days later) » 

17:08
0
Q: Интеллектуальный интерфейс (God object) неизбежен при использовании дизайнера WinForms?

James BondОставиваю мелкими шажочками WinForms) Не мог не заметить, что если использовать для создания формы только дизайнер, то возникает нечто похожее на антипаттерн Интеллектуальный интерфейс (God object), т.к. файл с кодом формы и файл дизайнера - это partial-классы, т.е. по сути один класс, просто под...

в принципе никак не связано с winforms
Что не связано, и почему не связано?) С WinForms не связано, но связано с дизайнером. О нем и вопрос
и с дизайнером не связано
Можно чуть более развернуто? Я надеюсь, под интеллектуальным интерфейсом мы понимаем одно и то же.
Я не понял связи интеллектуального интерфейса (это что вообще?) и антипаттерна god object? Более того, god object - означает объект, который делает все или слишком много всего, как накликанные формы с этим связаны тоже не понятно.
17:08
То, что файл дизайнера может быть очень большим, не имеет значения: на сгенерированный код принято не обращать внимания. А в файле с кодом должны быть только привязки данных и вызовы сервисов. Надеюсь, вы не пишите бизнес-логику в баттонкликах?
ИИ - частный случай god object. То есть интерфейс, который сам определяет и свой внешний вид, и свое поведение, что и происходит при использовании дизайнера. В норме же в классе формы должна описываться только форма, а ее поведение должно быть описано в другом классе. Так лучше?
интерфейс, который сам определяет и свой внешний вид, и свое поведение - а какие еще бывают интерфейсы?
интерфейс, который сам определяет и свой внешний вид а зачем нужен интерфейс, который не определяет свой вид? Мне кажется, вы немного запутались в терминологии. Плюс, если вы пишете всю логику вашей программы в файлах форм - это вы делаете из форм god object, сами по себе формы - это просто сгенерированные классы уровня представления.
А вообще, дотнет и винформы создавались ещё в прошлом веке... Тогда ещё не были так формализованы паттерны и методики хорошего проектирования.
@AlexanderPetrov, я только учусь. Поэтому не мог не заметить, что такая ситуация возникает. Grundy, бывают еще нормальные) tym32167, я не запутался, перечитайте.Интерфейс должен определять свой внешний вид, и только его. Но если использовать дизайнер так, как это часто делают разные "учителя", то обработчики будут создаваться в том же файле, в котором описана форма. Кроме того, в коде, описывающем форму, есть еще подписки на события, и вот это уже явное нарушение - подписываться должны сами классы с логикой, а не форма должна их подписывать. Хотя бы для того, чтобы можно было отписаться.
17:08
Все эти события и обработчики - это детали интерфейса и только его, там им место. Почитайте про какой нибудь паттерн для форм, типа MVP или что там было для них популярно. Использовать дизайнер или нет - с точки зрения работы с формами не принципиально, у вас просто будет больше мусора в коде и все. А вот чтобы это превратить в god object - это уже вам самому надо неправильно с классом формы работать и перегрузить его лишним.
@JamesBond Grundy, бывают еще нормальные - какие например?
17:24
@tym32167 я сейчас больше с формальной точки зрения оцениваю - правильно делаю или неправильно. Если это нарушение, на которое обычно принято закрывать глаза - ок, но важно понимать, что это не норма. Если говорить о паттернах, то я даже не представляю, какой можно прикрутить к тому коду, что создается дизайнером. С моей точки зрения должно быть так: есть класс формы, который определяет свой внешний вид. Другие классы подписываются на нужные события (сами!) и определяют для них обработчики.
@AlexanderPetrov просто увидев один раз нормальный код, делать "как-нибудь" или "как решит сама форма" уже не хочется)
@Grundy бывают еще интерфейсы, которые НЕ определяют поведение программы)
@JamesBond например?
@JamesBond в чем отличие от того, что получается у тебя?
17:41
@Grundy какой пример вы хотите? Я уже описал суть в нескольких сообщениях выше. Есть, например, калькулятор. Его класс формы описывает размер окна, положение поля для ввода, размер и положение кнопок и надписи на них. Всё. А уже классы с логикой подписываются на интересующие их события формы, обрабатывают введенные данные, и связывают, например, кнопки с данными на дисплее.
@JamesBond ты пишешь что бывают еще интерфейсы, которые НЕ определяют поведение программы) - я прошу у тебя пример такого интерфейса. Ты его видел где-то или только предполагаешь, что по твоему мнению он должен работать так-то и так-то?
@Grundy Разумеется, видел, иначе у меня бы вопрос не возник. Вот пример антипаттерна, в следующем же уроке показано как следует делать.
@JamesBond следующий - это какой?
@Grundy "Использование MVC".
@JamesBond лучше ссылкой
17:51
https://ulearn.me/course/basicprogramming2/Ispol_zovanie_MVC_b26a09d9-7af9-49c7-9d98-63930a19e9cf
Это следующий
@JamesBond так, и какая тут связь winforms и god object? 🤔 если не делать god object его и не будет, от win forms тут ничего не зависит
18:16
@Grundy да при чем тут WinForms? Речь не о нем, а конкретно о дизайнере. У нас создается partial-класс Form1.cs и *.Designer.cs. Но по сути это один класс, просто разделенный на два файла. Соответственно, что мы создаем обработчик автоматически, кликнув по кнопке на форме, что напишем его руками - он будет в классе с формой.
@Grundy Соответственно, либо мы создаем для логики отдельный класс и в нем подписываемся на все что нужно и обрабатываем как положено - но тогда класс Form будет пустым. Либо создаем в классе Form обработчики, а из них вызываем нужную логику, но тогда это ломает событийную модель и делает невозможной отписку от событий.
@JamesBond не понял логику
@JamesBond *.Designer.cs - просто содержит boilerplate код, который был бы написан в любом случае, просто сейчас он генерируется автоматически. Он никак не влияет на интеллектуальность интерфейса
@JamesBond про невозможность отписки не понял. пустым класс форм не будет, так как в нем находится описание интерфейса ¯\_(ツ)_/¯
@Grundy Я не знаю, как еще объяснить. В уроках по ссылкам все разъяснено предельно ясно, показано и как надо делать и как не надо. Если вы видели дизайнер и генерируемый им код, и не понимаете суть вопроса, то я не знаю как еще объяснить.
@JamesBond а ты видел дизайнер и генерируемый им код? Что в нем по твоему нагененировано?
@Grundy я уже объяснял. Как минимум то, что он сам подписывает обработчики на свои события.
@JamesBond в дизайнере? в файле *.Designer.cs ?
18:29
@Grundy Да.
@JamesBond очень странно, такого там нет, как ты это проверял?
@Grundy создайте на форме кнопку и обработчик для любого события этой кнопки (через дизайнер, разумеется). Далее зайдите в *.Designer.cs и в области, помеченной как "#region Код, автоматически созданный конструктором форм Windows" увидите подписку на выбранное событие.
18:51
@JamesBond все, увидел про что ты. Проблемы все еще нет - это буквально настройка интерфейса. Если хочешь отписаться - никто не запрещает выбрать соответствующий контрол и отписаться
19:09
@Grundy это не настройка интерфейса, я уже замучался объяснять. Подписка на интересующие события - это прерогатива логики, а не самого интерфейса. Интерфейс определяет представление, и больше ничего, не говоря уже об обработчиках.
@JamesBond если вас смущает, что там 2 файла, а не один - это хак для поддержки генерации кода, один файл генерится, во втором пишет программист - это не страшно и ничего не ломает. Если смущает, что класс окна сам подписывается на свои события - это внутренняя деталь имплементации окна, внутри себя любой класс может творить любую дичь, это ничего не нарушает пока класс занимается своим делом - обслуживанием окна в даннм случае.
@JamesBond в данном случае настройка ¯\_(ツ)_/¯
God object - это объект, который делает всё, то есть не ясна его область действия, условно он и в БД ладазет, и по сети что то запрашивает, и данные валидирует и рисует и танцует - в общем, делает веши разной темы.
Класс окна же занимается по идее одной задачей - представлением пользователю окна, то есть предоставлением юзеру возможности работать с программой, отображением какиз то данных из вашего ПО и вносом каких то данных в ваше ПО. Если ваш класс окна делает что то еще - это уже только если вы сами туда лишнего добавили.
@tym32167 ну так а куда это "лишнее" будет добавляться, если продолжить создавать обработчики так, как потворствует дизайнер? В класс окна. Об этом и вопрос. Я могу согласиться, что пока обработчики обслуживают задачи представления, то пофигу как они генерируются. Но значит программную логику с помощью дизайнера уже создавать нельзя, а нужно вручную подписываться на нужные события и обрабатывать их. Вы это имели ввиду?
19:27
@JamesBond нет. Вы считаете, что событие окна как то отночится к логике - но оно не относится к логике. Если юзер что то кликнул или выбрал в окне - это всё еше тема обслуживания окна. Окно может вызвать класс с какой то релевантной бизнес логикой или может не вызвать - так как это и есть прямое назначение окна, быть слоем между юзером и логикой программы вашей.
Вот было бы там не событие, а что то другое, это что то изменило бы? Было бы не окно, а консоль, там были бы оконнче события? Была бы не консоль, а веб сервер и веб запросами - оно что то поменяло бы для приложения? Правильный ответ - нет, если вы можете окно заменить на консольные команды и приложение продолжит работать - вот тогда вы отвязали логику от представления
19:38
@tym32167 представьте пример с калькулятором. Мы ввели пару чисел и требуемую математическую операцию - числа записали в поля формы, бог с ними, пусть так. Но дальше нажимаем "=". Где должен находиться обработчик, который посчитает результат? Откуда он возьмет аргументы? Как этот обработчик изначально подписывался на событие "="? Надеюсь, находится он не в классе Form - потому что это и есть чистая логика, не имеющая отношение к представлению, но почему-то создающаяся в одном с ним классе.
@JamesBond обработчик события формы - очевидно относится к представлению. Что в нем будет записано уже вопрос ¯\_(ツ)_/¯ если пишешь логику напрямую в нем выдирая данные из компонентов формы - могут быть проблемы, если пробрасываешь в слой логики и получаешь результат - проблем нет
@JamesBond у вас должен быть класс, который принимает выражение и вычисляет его результат. Тому классу всё равно как это вырежение к нему попадет и как будет использовал результат выражения. Этому классу все равно, есть ли где то кнопка = вообще или нет. Всё, что класса интересует - это выражение на входе и результат на выходе.
@JamesBond тот факт, что форма может вызвать этот класс чтобы посчитать результат выражения - это класс логики не заботит. Будет у вас консольное приложение или что еще будет вызывать класс логики - классу логики всё равно
@JamesBond само существование обработчика в классе окна - это чисто деталь работы окна, кроме окна это больше никому не интересно, что у окна есть обработчник и это больше ни на что не влияет
20:01
@JamesBond чтобы было ясно: извлечение значения полей и передача этих значений в класс для расчета выражения, считываегте результата и запись этого результата в поле формы - это все часть логики представления и должна жить где то в окне. Процесс извлечения того, что ввел юзер - это не основная логика вашего приложения, это просто какой то код, помогающий взаимодейстовать юзеру и классу расчета выражения и место ему в окне.
@JamesBond в некоторых паттернах, типа MVVM, добавляют еще слой между вашей логикой и отображением - называется ViewModel, вам оно может больше понравится, но, если я верно помню, оно не применимо в WinForms
@JamesBond Например, если бы вы говорили не про WinForms, а про WPF - там писать руками обработчики плохая практика, потому что WPF поддерживает биндинги, а значит там можно использовать MVVM паттерн, где между представлением и логикой есть промежуточный слой View Model
@JamesBond но, в конечном итоге, если у вас есть класс, который принимает выражение и возвращает результат, то ему все равно, напрямую его вызывают из окна или его вызвают из VM или как то иначе
@tym32167 где-то был пример как в forms делали mvvm - возможно даже тут вопрос был
20:17
@JamesBond Если говорить про паттерны для ВинФорм конкретно,то вы можете следовать MVP grantwinney.com/its-possible-to-test-a-winforms-app-using-mvp - там идет разделение окна и обработчиков. Когда вы обработчики храните в окне - это не делает окно god объектом, вы просто не следуете паттерну в этом случае.
@Grundy да я не сомневаюсь, просто мало кто такую экхотику будет использовать )
@tym32167 я, кончно, еще совсем "зеленый", чтобы рассуждать про инкапсуляцию, принцип единственной ответственности и т.п., но глаз все равно дергается, когда смотрю на код в винформах) Вы сказали, что делая обработчики в окне я просто не следую паттерну - но так я как раз и пытаюсь ему следовать, просто не понимаю, как это делать при использовании дизайнера.
@tym32167 Единственное, что приходит в голову - пускай окно рисуется как хочет, а логика размещается в отдельном классе (классах), оттуда подписывается на нужные события, и обрабатывает их как положено. Тогда, с горем пополам, можно соблюсти и MVC (у нас на курсе именно этот паттерн рассматривался), и в интеллектуальный интерфейс не скатиться.
@tym32167 я почему об это головой бьюсь - боюсь, приду устраиваться на первую работу, там посмотрят мои проекты, ткнут носом в код дизайнера и спросят с круглыми глазами: "Это, блин, что?..")))
@Grundy обработчик события формы - смотря какой это обработчик. Если он управляет, скажем, кнопочкой, которая должна перекрашиваться при наведении - ок, с этим можно жить. Но если он отвечает за логику самого приложения (например, складывает числа в калькуляторе), то это уже явное нарушение MVC. Я ведь рассуждаю именно в контексте соблюдения паттерна, а не просто "получится или не получится"...
20:39
@JamesBond никто не буДет смотреть твои проекты ¯\_(ツ)_/¯
@Grundy все равно ачкую))))
@JamesBond ты все еще путаешь обработчик, который реагирует на событие в форме и выполнение логики самого приложения(например, складывает числа в калькуляторе) - ты можешь запихнуть логику в обработчик, но можешь и не запихивать ¯\_(ツ)_/¯
@JamesBond следование или не следование паттерну MVC не делает форму god объектом, то есть нет связи между MVC и антипаттерном god object, это вещи ортогональные, одно другое не отменяет. Касательно дизайнера - хз как в вин формах, но в WPF профессионалы не пользуются дизайнером :)
@Grundy я не путаю, разве что мы просто подразумеваем разные вещи под словом "обработчик". Вкратце - есть событийная модель, основанная на делегатах (как раз то, что мы с вами нашли таки в классе дизайнера). Делегаты допускают множественную подписку (мультиделегат), и выполняет все подписанные методы при вызове делегата. Все "желающие" (обработчики разных классов) подписываются на интересующие события, и обрабатывают их по своему усмотрению.
@Grundy В WinForms же все идет наоборот - не от обработчиков к событиям, а от событий к обработчикам, да еще и создает их хрен пойми где.
@JamesBond обработчик не должен складывать числа - максимум вызывать метод другого класса, который умеет складывать. Это если отделять логику от представления
20:52
@JamesBond это сообщение не понял
@Grundy вы сказали, что я путаю обработчик события с логикой приложения. Я попытался объяснить, что я подразумеваю под обработчиками.
@JamesBond я про сообщение про winforms
@tym32167 так, а вот это уже что-то. То есть самое большее, что может делать такой автоматически сгенерированный обработчик (для кнопки, например) - вызывать заинтересованные методы из классов с логикой? Я верно понял вашу мысль?
@Grundy может не совсем удачно выразился - я имел ввиду, что в дизайнере не обработчики сами подписываются куда захотят, а событие подписывает на себя конкретный обработчик. Просто для меня это так выглядит, не берите в голову)
@JamesBond это не так. от того что код пишется автоматически а тебе выставляется функция которую нужно заполнить ничего не меняется, ты точно так же можешь руками сделать то же самое.
21:11
@Grundy да так-то можно и в блокноте все писать, дело нехитрое. Препод как раз и призывает описывать форму кодом, без дизайнера - там все получается чики-пуки. Но я понял, что если буду учить все существующие свойства и события, то просто свихнусь)) И так на два месяца в прокрастинацию выпал от этих винформов))
@JamesBond без дизайнера слишком много кода требуется писать. нет смысла руками делать то, что отлично делается автоматически
@JamesBond И не только автоматически сгенерированный. Неважно как сгенерирован обработчик на форме, если вы хотите разделить логику и представление, вам надо держать логику в одних классах и представления в других. А значит, если представлению надо выполнить какую то логику, они должны вызвать методы классов логики для этого
@tym32167 но тогда получается, что событийная модель используется неправильно. Грубо говоря - зачем-то создается этот самый обработчик, вызывающий нужные методы. Почему не оформить все методы, которые должны выполнять обработку, как стандартные обработчики, и не подписать их на нужные события? На курсе, который я прохожу, учат так.
@tym32167 плюс можно вспомнить принцип открытости-закрытости. Если нужно убрать какой-то метод из логики, то нужно будет лезть в обработчик в классе формы. Если же классы с логикой будут сами подписываться непосредственно на событие, то их можно будет и отписать или вообще удалить из программы, не затрагивая класс формы.
 
2 hours later…
23:40
@JamesBond вы должны понимать, что есть какая то бизнес логика приложения, а есть представление (условно, окно) - и все эти телодвижения с событияи/обработчиками предназначены только чтобы связать представвление с логикой. ВЫ можете связывать представление с логикой через обработчике в окнах или ввести отдельный какой то слой для этого - это уже вам решать, тут идеального решения нет, есть только какие то рекомендации типа использования паттернов MVC/MVP.
@JamesBond если классы логики будут подписываться на события, то это означает, что классы логики будут знать вообще о том, как устроено представление у вас - что там есть события. У вас получится что хвост виляет собакой. Вы про принципы знаете - вам про D из SOLID надо почитать и определиться, где у вас модули верзнего уровня и где нижнего.
@JamesBond принцип открытости и закрытости немного про другое, можете почитать тут ru.stackoverflow.com/a/889202/179763
@JamesBond в дополнение, я выше приводил вам пример. Вот у вас калькулятор, в нем класс отвечает за вычисление выражения. Если бы этот класс подписывался на какие то события окна, смогли бы вы его использовать там, где окон нет, например в консоли? Не смогли бы, а значит классы логики, которые знают про события окон, привязаны к окнам и не могут быть использованы без окон. А это нарушает всё, что можно нарушать, начиная от S из SOLID и заканчивая высокой связностью.
@JamesBond при высокой связности и нарушении S из SOLID, когда вам надо будет добавить реакцию на новое событие, вам это событие придется описать в окне и в логике, что противоречит S и ломает вам O из того же SOLID.
@JamesBond смысл этих паттернов типа MVC/MVP/MVVP/etc, как и всяких прочих - отделить мух от котлет, чтобы если вам надо было от мух избавиться - вам не пришлось портить котлеты при этом. Но как именно вы их отделяете - это уже вам решать, хотите - пихайте 100500 абстраций, хотите - просто избегайте логики в обработчиках, тут каждое решение должно быть к месту, универсального решения в природе нет.

  last day (16 days later) »