Як можна найкраще уникати написання роздутого GUI-коду?


48

Я виявляю, щоразу, коли я працюю з кодом графічного інтерфейсу, код, як правило, розширюється швидше, ніж інші види коду. Це також здається важчим для рефактора. В той час, як в інших видах коду я можу відновити рефактор досить легко - я вважаю, що можу розкласти більший клас на більш дрібні фрагменти функціональності - в більшості фреймворків графічного інтерфейсу я часто пов'язаний з рамкою, яка вимагає від мого віджета / управління / будь-якого класу реалізувати набагато більше речей безпосередньо у віджеті / контролі / будь-що інше. Іноді це пов’язано з необхідністю або (а) успадковувати якийсь базовий віджет / контроль / річ, або (b) потребувати доступу до захищених методів.

Як правило, мені також доводиться, наприклад, реагувати на різноманітні входи через сигнали / події / що завгодно з рамки, щоб реалізувати всі режими взаємодії з користувачем. Мені може знадобитися один віджет / елемент управління GUI, щоб обробляти велику різноманітність вводу / виводу, яка може включати:

  1. клацання правою кнопкою миші / контекстне меню
  2. реагування на виділення з контекстного меню - яких може бути багато
  3. особливий спосіб малювати графічний інтерфейс
  4. реагують на введення клавіатури
  5. кнопки, прапорці,
  6. тощо

... весь цей час керуйте класами під графічним інтерфейсом, що представляють бізнес-логіку.

Простий графічний інтерфейс може швидко зростати, навіть коли відокремлена логіка покупки та використання MVC, я вважаю, що код GUI є великим магнітом для змін.

Чи є спосіб управління GUI-кодом достойним способом і не допускати його розбиття вікна? Або ж маса обробників випадкових подій / перекритих методів дійсно найкраще, що ми можемо зробити для GUI-коду?


4
Яке ваше точне визначення поняття "подуття"?

Відповіді:


36

Що потрібно пам’ятати про код GUI, це те, що він керується подіями, а керований подіями код завжди матиме вигляд маси випадково організованих обробників подій. Там, де це стає справді безладним, коли ти намагаєшся внести в клас код, що не керує подіями. Звичайно, він виглядає як підтримка обробників подій, і ви можете зберігати обробників подій красивими і маленькими, але весь цей додатковий код підтримки, що плаває навколо, робить ваш джерело GUI здається роздутим і безладним.

Отже, що ви можете зробити з цього приводу, і як зробити речі простішими для рефактора? Ну, я б спершу змінив своє визначення рефакторингу від чогось, що я роблю при нагоді, на те, що я роблю постійно, коли кодую. Чому? Тому що ви хочете, щоб рефакторинг дозволив вам легше змінювати код, а не навпаки. Я не просто прошу змінити семантику тут, але прошу вас зробити трохи розумової гігієніки, щоб побачити ваш код по-різному.

Три методи рефакторингу, які, як я вважаю, використовую найчастіше - це перейменування , метод вилучення та клас вилучення . Якби я ніколи не дізнався жодного іншого рефакторингу, ці троє все-таки дозволять мені зберегти свій код чистим та добре структурованим, і зі змісту вашого запитання мені здається, що ви, ймовірно, опинитесь у тих самих трьох рефакторингах майже постійно в щоб ваш код GUI був тонким і чистим.

Ви можете мати найкраще можливе розділення логіки GUI та Business у світі, і все-таки код GUI може виглядати так, що в середині нього був підірваний мін коду. Моя порада полягає в тому, щоб мати додатковий клас або два, щоб допомогти вам правильно керувати графічним інтерфейсом, і це не обов'язково, щоб бути класами View, якщо ви застосовуєте шаблон MVC - хоча часто ви знайдете посередницькі класи настільки схожі на ваш погляд, що ви часто будете відчувати бажання об'єднати їх для зручності. Я вважаю, що додавати додатковий шар, специфічний для графічного інтерфейсу для управління всією візуальною логікою, не дуже шкодить, однак, ймовірно, ви хочете зважити переваги та витрати на це.

Тому моя порада:

  • Не робіть нічого безпосередньо за вашим графічним інтерфейсом, окрім як викликати та визначати, як графічний інтерфейс підключиться до перегляду (або посередницького шару).
  • Не намагайтеся підключити кожну річ, пов’язану з переглядом, в один клас - або навіть один клас у вікні графічного інтерфейсу, - якщо для вас це не має сенсу. Ваша альтернатива полягає в створенні безлічі маленьких і простих в управлінні класами для управління вашою логікою графічного інтерфейсу.
  • Коли ваші методи починають виглядати трохи більше, ніж на 4-5 рядків коду, вивчіть, чи це необхідно, і чи можливо витягнути метод або два, щоб ви могли зберегти ваші методи, навіть якщо це означає клас за допомогою багатьох інших методів.
  • Якщо ваші заняття починають виглядати справді великими, почніть з видалення ВСІХ дублюваних функціональних можливостей, а потім подивіться, чи можете ви логічно згрупувати свої методи так, щоб ви могли витягти ще один клас або два.
  • Подумайте про рефакторинг щоразу, коли ви пишете рядок коду. Якщо ви отримаєте рядок коду для роботи, подивіться, чи зможете ви переробити його, щоб уникнути дублювання функціональності або зробити його трохи меншим, не змінюючи поведінку.
  • Прийміть неминуче, що ви завжди будете відчувати, що та чи інша частина у вашій системі почне відчувати себе трохи роздутою, особливо якщо ви нехтуєте рефакторингом під час руху. Навіть маючи кодову базу коду, ви все ще можете відчувати себе так, ніби є більше, що ви можете зробити. Це реальність написання програмного забезпечення, що ви завжди відчуєте, що щось більше можна було зробити "краще", тому вам потрібно досягти балансу між професійною роботою та золотою обробкою.
  • Прийміть, що чим чистіше ви намагаєтеся зберегти свій код, тим менше видається ваш код.

3
+1 Подобається чи ні, графічний інтерфейс піклується про деталізовані операції на мільйон, а це означає код.
Патрік Х'юз

Розробники повинні навчитися використовувати кодування, кероване подіями для GUI.
Девід Гао

23

Я думаю, що багато проблем, з якими ви стикаєтеся, можна віднести до простої причини. Більшість розробників не трактують код GUI як "реальний" код. Я не маю тут жодних доказів чи статистичних даних, просто почуття кишечника.

Можливо, вони вважають, що це " просто презентація " і не важливо. " Тут немає ділової логіки ", вони кажуть: " навіщо це тестувати "? Вони сміються, коли ви згадуєте орієнтацію на об'єкт і пишете чистий код. Вони навіть НЕ ПІДТРИМУЮТЬ, щоб покращити справи. Немає структури для початку, вони просто ляпають якийсь код і дають йому гнити, оскільки інші додають власний штрих з часом. Гарний безлад, графіті код.

Код GUI має свої унікальні проблеми, тому до нього слід ставитися по-різному та з повагою. Їй потрібна любов і розробники, які хочуть її написати. Ті, які зроблять його тонким і нададуть йому гарну структуру та правильні візерунки.


2
+1 за натяк на сприйняття коду GUI, який трактується по-різному, ніж код не-gui. Я втратив підрахунок кількості разів, коли я чув, як хтось сказав: "Не намагайтеся тестувати графічний інтерфейс, тому що це не рентабельно, і до того ж це важко зробити". Я зазвичай перекладаю на "Це важко, і я лінивий, щоб навчитися це робити!".
S.Robins

1
+1 Де я працюю, ми часто не переглядаємо код GUI - "це просто графічний інтерфейс, пропустити його". І я така ж винна, як ніхто. Дивна річ у тому, що в моїх особистих проектах я витрачаю багато, якщо час намагаюся отримати гарний чистий GUI-код. Здогадайтесь, це просто культура.
HappyCat

8

Чомусь код GUI створює сліпу пляму у розробників щодо розділення проблем. Можливо, це тому, що всі підручники збивають все в один клас. Можливо, це тому, що фізичне представлення робить речі здаються більш тісними, ніж вони є. Можливо, це тому, що заняття збираються повільно, щоб люди не визнавали, що їм потрібно рефакторинг, як, наприклад, жабу, яка прокидається, повільно піднімаючи тепло.

Незалежно від причини, рішення - зробити ваші заняття набагато меншими. Я роблю це, постійно запитуючи себе, чи можна перенести те, що я набираю, в окремий клас. Якщо можливо перейти в інший клас, і я можу придумати розумне і просте ім’я для цього класу, то я це роблю.


6

Можливо, ви захочете поглянути на модель Презентація / Пасивний вигляд моделі. Рей Райан добре поговорив в IO Google про найкращі архітектурні практики для GWT.

http://www.google.com/events/io/2009/sesions/GoogleWebToolkitBestPractices.html

Легко абстрагувати ідеї до інших рамок та мов. Основна перевага MVP (на мою думку) - одинична перевірка. І ви це отримуєте лише в тому випадку, якщо ваш код, який не роздутий і не спагетті (судячи з вашого питання, це те, що ви хочете). Він працює, вводячи логічний шар подання, який називається презентатор. Фактичний вигляд відключається від цього через інтерфейс (і, таким чином, можна легко висміюватися в одиничних тестах). Тепер, оскільки ваш логічний рівень перегляду (презентатор) звільнений від внутрішніх частин конкретного графічного інтерфейсу, ви можете організувати його як звичайний код і не пов'язаний, наприклад, з ієрархією спадкування Swings. В ідеалі ви можете перемикати реалізацію графічного інтерфейсу в різних рамках, якщо вони відповідають одному інтерфейсу.


1
+1. MVP фокусується саме на тому, як вивести логіку GUI в окремі класи, що часто сильно відрізняється від того, що люди розуміють, коли вони говорять про MVC.
Док Браун

5

Моя відповідь складається з чотирьох частин: структура, простота, тестування та синтаксис.

Перші три справді важко зробити!

Структура означає приділяти багато уваги використанню найменшої кількості коду та максимальної кількості фреймворків, бібліотек тощо.

Простота означає простоту речей від початкового проектування до реальної реалізації. Зберігати навігацію простою, використовуючи прості плагіни, зберігаючи макет досить "рівним", тут все допоможе. Тепер вони можуть бути «продані» клієнтам / користувачам, які можуть швидко побачити переваги сторінок, які працюють на ПК, ipad, мобільних та інших пристроях.

Засоби тестування, включаючи інструменти для тестування браузера (веб-сайт і capybara приходять до тями при роботі з моїми рейками), які вирішують проблеми перехресного браузера наперед, коли кращий код може бути розроблений для боротьби з ними на початку, на відміну від частого "виправлення" коду різними розробниками, оскільки їх "відкрили" користувачі різних браузерів.

Синтаксис. Дійсно корисно використовувати перевірку коду / IDE / редактор-плагін тощо для своїх HTML, CSS, Javascript і т. Д. Перевага, яку одержали браузери завдяки тому, що вдається обробити неправильно сформований HTML, працює проти вас, коли різні браузери працюють по-різному це, тому інструмент, який перевіряє ваш HTML-формат, є важливим. Добре сформований HTML дуже допомагає розблокувати HTML, оскільки поганий код повинен мати більшу видимість.


4

Я знайшов рішення декларативний код. Використання просто процедурного коду - це рецепт GUI-коду спагетті. Звичайно, "особливий спосіб малювати віджет", ймовірно, залишиться кодом. Але це код, виділений у класі. Обробники подій, комбінації клавіш, розміри вікон - все, що брудно, найкраще задекларувати.


4

Тут багато чудових відповідей.

Одне, що допомогло мені спростити код GUI, - це переконатися, що у GUI є своя модель даних.

Для простого прикладу, якщо у мене є графічний інтерфейс із 4 полями введення тексту, у мене є окремий клас даних, який зберігає вміст цих 4 полів для введення тексту. Складніші графічні інтерфейси вимагають більше класів даних.

Я проектую графічний інтерфейс як перегляд моделі. Модель GUI управляється контролером програми прикладного контролера модель - view - view. Перегляд програми - це модель GUI, а не сам код GUI.


2

Такі програми, як Word Processing, графічні редактори тощо, мають складні інтерфейси, і їх код не може бути простим. Однак для бізнес-додатків графічний інтерфейс не повинен бути таким складним, але деяким, яким він є.

Деякі з ключів до спрощення графічного інтерфейсу є (більшість стосується .NET):

  1. Прагніть до спрощення дизайну, коли це можливо. Уникайте фантазійної поведінки, якщо бізнес не вимагає цього.

  2. Використовуйте хороший постачальник засобів управління.

  3. Не створюйте власні функції керування у самому коді клієнта. Натомість створіть керування користувачами, що розширює оригінальний елемент управління таким чином, щоб ви могли відобразити ваші конкретні поведінки в елементах управління, а не в коді використовуючої форми / сторінки.

  4. Використовуйте рамку (навіть домашню) для обробки інтернаціоналізації, управління ресурсами, стилів тощо, щоб ви не повторювали цей код у кожному інтерфейсі.

  5. Використовуйте компонент (або рамку) для навігації.

  6. Побудувати стандартні діалоги про помилки, попередження, підтвердження тощо.


1

Застосуйте об'єктно-орієнтований дизайн до свого коду та для розробки інтерфейсу:

  1. Окрема презентація та модель Використовуйте бібліотеку / фреймворк незалежно від MV або напишіть власну, щоб допомогти відокремити логіку перегляду / контролера від моделі даних. Вся комунікація з бекендом повинна здійснюватися всередині моделі, а стан моделі завжди повинен бути синхронізований із резервним.
  2. Розв'язка Якщо об’єкт A знає про об'єкт B, то A може викликати методи на B, але B не повинен знати про A. Натомість A може слухати події від B. Це гарантує, що немає кругової залежності. Якщо у вашому додатку багато подій між компонентами, створіть EventBus або використовуйте рамки, керовані подіями, такі як Twitter Flight.
  3. Часткове та повне візуалізація Якщо ваш погляд є таблицею або списком елементів, вам може сподобатися створити такі способи, як "додати", "видалити", щоб вставити / видалити один елемент у колекцію /. Ваш код може легко розмитись, коли вам доведеться підтримувати сортування та пагинацію. Тому моя порада: просто перегляньте весь погляд навіть тоді, коли є часткова зміна. А як щодо продуктивності? Добре, якщо ваша колекція велика, то все одно слід робити пагинацію. Веб-розробник: переконайтеся, що ваші обробники подій делеговані кореневому елементу подання, який не змінюється.
  4. Перегляд моделі Коли стан вашого перегляду стає занадто складним для підтримання, наприклад, у таблиці Таблиця повинна відслідковувати дані рядків, дані стовпців, порядок сортування, поточні рядки, що перевіряються (якщо він підтримує багатопроверку) тощо, ви, ймовірно, повинні створити об’єкт ViewModel для цих станів. Ваш об’єкт View повинен викликати налаштування у ViewModel, якщо в інтерфейсі щось зміниться (наприклад: користувач перевіряє рядок); і він повинен відповісти на зміну ViewModel, оновивши інтерфейс користувача. Зазвичай вам слід уникати оновлення інтерфейсу користувача, якщо подія зміни викликає інтерфейс користувача.

Ось невеликий, але нетривіальний додаток, який допоможе проілюструвати деякі мої моменти. Діаграму взаємодії з кодом та переглядом / моделлю ви можете знайти тут: https://github.com/vanfrankie/pushpopbox


0

Ви хочете поглянути на поняття "прив'язка даних" . Це спосіб з'єднати елементи інтерфейсу з абстрактними елементами моделі декларативним чином, щоб елементи моделі автоматично синхронізувались із вмістом інтерфейсу користувача. У цьому підході є багато переваг, наприклад, не потрібно самостійно писати обробники подій для синхронізації даних.

Існує підтримка прив'язки даних для багатьох фреймворків інтерфейсу, наприклад .NET і Eclipse / JFace .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.