Почему следует избегать наследования форм?


9

Я помню изучение VB4 и перетаскивание кнопки на форму, двойной щелчок по этой кнопке и ввод кода в тот обработчик событий, которым я только что получил магическое благословение. Придя из QBASIC, я был в восторге от «V» в «VB», визуальный дизайнер был буквально лучшей вещью со времен нарезанного хлеба.

Конечно, вы можете делать все это программно, но магия «V» была настолько привлекательной, что вы просто не могли удержать эту кнопку. Мы были поощрены пойти по этому пути.

Но затем, несколько лет назад, я начал изучать C # и .net framework и был очарован тем, как все, что я думал, что я знал, только что вышло из окна. В VB6 происходит много магии, которая полностью раскрыта в .net: например, конструкторы и InitializeComponentsметод. В последнем вы найдете все экземпляры элементов управления, которые вы перетаскивали из панели инструментов, все события, которые вы зарегистрировали, и свойства, которые вы установили в конструкторе.

И это нормально ... Я думаю. Просто я чувствую, что не «владею» тем, что происходит, этот код, который я могу изменить только через дизайнера, раздражает меня до чертиков. Каждый раз, когда вы копируете кнопку с надписью «ОК» из одной формы в другую (иногда вместе с ее братом «Отмена»), вы на самом деле дублируете код, и это не грех ? СУХОЙ, не повторяйся, говорит папа .

Не говоря уже о религиях и школах мысли, со всей объективностью, не должны ли мы вместо этого извлекать формы из базовых форм, и чтобы кнопка «ОК» (и все ее друзья) жили в базовой форме? Нечто подобное, FormBaseиз которого происходит DialogFormBase; все классы созданы в кратчайшие сроки ... набрав код. Кнопки создаются в зависимости от того, как создается экземпляр класса (т. Е. Аргумент перечисления конструктора определяет, какие кнопки должны быть созданы), элементы управления размещаются внутри расположения разделенных панелей и панелей разметки потока, внедряемых в форму какContentэто вписывается в основную панель контента. Разве это не то, что ASP.net делает с мастер-страницами и заполнителями контента? Я бы получил форму, когда мне нужна новая «мастер-страница», но эта «мастер-страница» по-прежнему наследуется от базового класса формы, поэтому визуальные эффекты едины во всем приложении.

Для меня это намного больше повторного использования кода, чем что-либо еще, что я когда-либо делал с конструктором в WinForms, и это не было даже сложно, и код не загроможден 200-строчным методом, который я не могу контролировать, я могу оставляйте комментарии там, где мне нравится, они не будут перезаписаны дизайнером. Я предполагаю, что это просто вопрос шаблонов и архитектуры, и именно это привело меня к этой ссылке: лучший дизайн для форм Windows, которые будут иметь общую функциональность , где я понял, что нахожусь на месте, кроме ответа, который предлагает именно то, что я делает, но это советует против наследования форм из соображений дизайнера. Эту часть я не понимаю .из- за соображений структуры кода, особенно в отношении наследования форм и элементов управления, которые я не вижу причин избегать, кроме того, что это нарушает конструктор .

Мы не можем быть просто ленивыми, так какую часть мне не хватает?


Я не понимаю Вы подразумеваете, что мы не должны использовать визуальные дизайнеры и писать весь код GUI вручную?
Euphoric

До .NET, где был код, который контролировал все объекты, перетаскиваемые в форме?
JeffO

1
@JeffO Судя по унаследованному коду, я бы сказал, прямо в форме, где-то между встроенным SQL и бизнес-логикой. Дело в том, что WinForms - это .net; поэтому, если дизайнер хорошо работает с тем, что в настоящее время пахнет «плохим кодом» и «плохими привычками кодирования», и на самом деле ломается, когда вы начинаете структурировать вещи, я говорю, бросьте дизайнер и трактуйте формы как то, что они (классы!) .. И как же кодирование уровня пользовательского интерфейса в C # так сильно отличается от кодирования уровня пользовательского интерфейса в ExtJS? Это «утомительно» делать в WinForms, потому что «эй, смотрите, есть дизайнер»? Кодирование ExtJS UI утомительно?
Матье Гиндон,

Я собираюсь процитировать другого пользователя: CodeCaster; Обработчик событий предназначен для подключения GUI к вашей бизнес-логике. Если у вас есть текстовое поле для ввода имени пользователя и кнопка «Добавить», нажатие кнопки «Добавить» должно просто вызвать _userRepository.AddUser (UsernameTextbox.Text). Вам не нужна бизнес-логика в обработчиках событий. stackoverflow.com/questions/8048196/…
Питер Б

@ Питер, разве это не помещает зависимость DAL в ваш уровень представления?
Матье Гиндон

Ответы:


9

Я собираюсь противопоставить вам другую парадигму: отдавайте предпочтение композиции, а не наследованию.

Даже если вы начнете писать код GUI вручную и используете наследование для обмена поведением и визуальными элементами между формами, вы столкнетесь с той же проблемой, что и обычный дизайн ООП. Допустим, у вас есть DialogForm с кнопками OK / Cancel и GridForm с сеткой. Вы выводите все диалоги из DialogForm и все формы с помощью Grid из GridForm. И тогда вы обнаружите, что хотите форму с обоими. Как бы вы решили это? Если вы используете наследование формы, то нет способа ее решить. С другой стороны, если вы используете UserControls, вы можете просто поместить GridControl в форму и покончить с этим. И вы все еще можете использовать конструктор с UserControls, так что вам не придется тратить время на написание утомительного кода GUI.


Итак, базовая форма просто имеет SplitContainer с фиксированной Panel2, которая содержит вызываемую FlowLayoutPanel BottomPanelи содержит обычные поведения Ok / Cancel / Apply / Close; Panel1 содержит SplitContainer с фиксированной Panel1 (для размещения общей метки «инструкций» или меню, панелей инструментов, что угодно, что вверху) и Panel2 с защищенной вызванной Panel MainContent; каждая фактическая реализация решает, как ее заполнить. Весь контент может быть внедрен в реализацию, и да, это может быть пользовательский элемент управления, созданный дизайнером, чтобы сэкономить время, хороший момент ... но как насчет самой формы?
Матье Гиндон,

Проблема здесь в масштабе. Когда вы принимаете заявку с 10 формами, то наличие единой общей формы не составляет большого труда. Проблемы начинаются, когда у вас есть приложение с десятками или сотнями форм. Тогда у вас будут формы, которые имеют общие части, но никогда не достаточно для создания базовой формы. В вашем случае, может случиться так, что вы захотите использовать другой макет или разные кнопки, но все остальное оставить прежним. И тогда начинаются проблемы.
Euphoric

2
«Проблема с масштабированием» не существует, если у вас наполовину приличный дизайн. У нас есть проект, в котором я работаю с несколькими сотнями форм. Мы интенсивно используем наследование форм для обеспечения согласованности и общей функциональности, и у нас никогда не было проблем с ним.
Мейсон Уилер

2
@MasonWheeler У меня был совершенно противоположный опыт. Мы пытались использовать наследование форм в одном из наших приложений, и каждый раз, когда мы вносили небольшие изменения в базовые формы, все это ломалось, и нам приходилось вручную исправлять все остальные формы. Кроме того, дизайнер ведет себя странно, когда вы работаете с унаследованной формой.
Эйфорическая

1
@Euphoric: какой дизайнер? Мы используем Delphi, и его дизайнер прекрасно работает с унаследованными формами. И опять же, у вас нет этих проблем, если у вас хороший дизайн . Если вы ничего не планируете, конечно, все будет хрупким и ломаться всякий раз, когда вы прикасаетесь к нему, но это ничем не отличается от любого другого кода.
Мейсон Уилер

2

Многое из этого связано с технологическим стеком выбора.

WinForms и WPF могут быть средами .NET UI, но могут сильно отличаться в достижении конечной цели. Некоторые парадигмы перемещаются между технологиями просто отлично, а другие нет, и вам не следует пытаться форсировать парадигму просто потому, что вы чувствуете, что она существует в каждой среде. Существует причина, по которой MVVM ориентирован на WPF / SL, а MVC - это отдельная концепция в ASP.NET от WebForms и так далее. Определенные технологии работают лучше с определенными парадигмами.

Имейте в виду, что сгенерированный код, как правило, должен быть удален из ваших проблем DRY Хотя это применимо в некоторых случаях, чаще всего его следует игнорировать. Понятия DRY, безусловно, должны оставаться в центре внимания за пределами уровня презентации, но на уровне представления сгенерированный код чаще всего является побочным продуктом структуры, в которой вы работаете. Это не означает, что вы не можете применять принципы DRY в своем подходе, но остаетесь осторожно. Не могли бы вы создать базовую форму и наследовать от нее бесконечно? Да. Могли бы вы перетаскивать компоненты на новую форму каждый раз, когда это необходимо? Да. Сосредоточьтесь на конечной цели, избегая потенциальных дефектов, упрощая рефакторинг в нисходящем направлении и масштабируемость, работая в пределах стека технологий, которые вы выбираете.


0

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

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


0

Я полностью согласен с Мейсоном Уилером, хотя через три года, возможно, даже он сам передумал.

Я пытаюсь найти альтернативы для перехода с исполняемых файлов Delphi на WEB.

До сих пор я решил использовать UNIGUI, потому что я все еще могу использовать наследование форм. Я бы хотел, чтобы у Delphi были такие Mixins, как Dart, так как это позволило бы мне иметь меньше предков. Но я чувствую, что люди пишут намного больше кода в MVC, чем с помощью Visual Form Inheritance, так как большая часть навигации, вызовы правил проверки в модуле данных (applyupdates), критерии фильтрации SQL, поиск в наборе данных клиента, все написано в 5, возможно, 6 Форма предков.

Даже «С MVC вам будет проще оставить Delphi в Feature», я не работаю в качестве аргумента, поскольку люди приглашали ООП, все это классы, свойства, методы. Так что все, что мне нужно, это переводчик. На самом деле не удалось найти никаких преимуществ, может быть, для веб-сайтов, которые гораздо менее сложны, но меняются в ежедневной базе.

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