Za każdym razem, gdy pracuję z kodem GUI, kod puchnie szybciej niż inne rodzaje kodu. Refaktoryzacja wydaje się również trudniejsza. Podczas gdy w innych rodzajach kodu mogę dość łatwo refaktoryzować - odkrywam, że mogę rozłożyć większą klasę na mniejsze części funkcjonalności - z większością struktur GUI często jestem związany ze strukturą, która wymaga mojego widget / control / jakiejkolwiek klasy zaimplementuj o wiele więcej rzeczy bardziej bezpośrednio w widżecie / kontroli / czymkolwiek. Czasami wynika to z konieczności (a) odziedziczenia niektórych podstawowych widgetów / kontroli / rzeczy lub (b) potrzeby dostępu do chronionych metod.
Zazwyczaj muszę także na przykład odpowiadać na dużą różnorodność sygnałów wejściowych za pośrednictwem sygnałów / zdarzeń / cokolwiek z frameworka, aby wdrożyć wszystkie tryby interakcji z użytkownikiem. Mogę potrzebować jednego widgetu / kontrolki GUI do obsługi wielu różnych danych wejściowych / wyjściowych, które mogą obejmować:
- menu prawym przyciskiem myszy / menu kontekstowe
- reagowanie na wybory z menu kontekstowego - których może być wiele
- specjalny sposób na malowanie GUI
- reagować na wprowadzanie danych z klawiatury
- przyciski, pola wyboru,
- itd itd
... cały czas zarządzaj klasami w GUI reprezentującymi logikę biznesową.
Prosty, prosty GUI może sprawić, że jego kod rozrośnie się dość szybko, nawet przy oddzielnej logice biznesowej i przy użyciu MVC, uważam, że kod GUI jest dużym magnesem do zmian.
Czy istnieje jakiś sposób na zarządzanie kodem GUI w rozsądny sposób i unikanie zepsucia okna? A może masa programów do obsługi zdarzeń losowych / przesłoniętych metod jest naprawdę najlepsza dla kodu GUI?
źródło
Odpowiedzi:
Należy pamiętać o kodzie GUI, ponieważ jest on sterowany zdarzeniami, a kod sterowany zdarzeniami zawsze będzie wyglądał jak masa losowo zorganizowanych procedur obsługi zdarzeń. To, co robi się naprawdę nieuporządkowane, jest wtedy, gdy próbujesz wprowadzić do klasy kod, który nie jest sterowany zdarzeniami. Jasne, wygląda na to, że zapewnia obsługę programów obsługi zdarzeń i możesz sprawić, by procedury obsługi zdarzeń były miłe i małe, ale cały ten dodatkowy kod pomocniczy unoszący się wokół sprawia, że twoje źródło GUI wydaje się nadęte i niechlujne.
Co więc możesz na to poradzić i jak ułatwić refaktoryzację? Cóż, najpierw zmieniłbym definicję refaktoryzacji z czegoś, co robię czasami, na coś, co robię ciągle podczas kodowania. Dlaczego? Ponieważ chcesz, aby refaktoryzacja umożliwiła łatwiejszą modyfikację kodu, a nie na odwrót. Nie proszę cię po prostu o zmianę semantyki tutaj, ale zamiast tego proszę o odrobinę mentalnej kalisteniki, aby inaczej zobaczyć kod.
Trzy najczęściej stosowane przeze mnie techniki refaktoryzacji to Rename , Extract Method i Extract Class . Gdybym nigdy nie nauczył się żadnego innego refaktoryzacji, te trzy nadal pozwoliłyby mi utrzymać kod w czystości i dobrze ustrukturyzowany, a z treści twojego pytania brzmi, jakbyś prawdopodobnie używałby tych samych trzech refaktoryzacji prawie stale w aby Twój kod GUI był cienki i czysty.
Możesz mieć najlepszą możliwą separację GUI i logiki biznesowej na świecie, a mimo to kod GUI może wyglądać, jakby kopalnia kodu została zdetonowana w środku. Moja rada jest taka, że nie zaszkodzi mieć dodatkową klasę lub dwie, które pomogą ci właściwie zarządzać GUI, i niekoniecznie muszą to być Twoje klasy View , jeśli stosujesz wzorzec MVC - chociaż często znajdziesz klasy pośredniczące są tak podobne do twojego poglądu, że często odczuwasz potrzebę połączenia ich dla wygody. Uważam, że dodanie dodatkowej warstwy specyficznej dla GUI do zarządzania całą logiką wizualną nie zaszkodzi, ale prawdopodobnie chcesz rozważyć korzyści i koszty związane z tym.
Dlatego radzę:
źródło
Myślę, że wiele napotkanych problemów można przypisać prostej przyczynie. Większość programistów nie traktuje kodu GUI jak „prawdziwego” kodu. Nie mam tutaj żadnych dowodów ani statystyk, tylko moje przeczucie.
Może uważają, że jest to „ tylko prezentacja ” i nieistotne. „ Nie ma tam logiki biznesowej ”, mówią „po co testować to urządzenie ”? Śmieją się, gdy wspominasz o orientacji obiektowej i pisaniu czystego kodu. Nie próbują nawet poprawić sytuacji. Na początku nie ma żadnej struktury, po prostu klepią trochę kodu i pozwalają mu gnić, gdy inni dodają swój własny dotyk w czasie. Piękny bałagan, kod graffiti.
Kod GUI ma swoje wyjątkowe wyzwania, dlatego należy go traktować inaczej i z szacunkiem. Potrzebuje miłości i programistów, którzy chcą to napisać. Te, które utrzymają go cienką i nadadzą mu dobrą strukturę i prawidłowe wzory.
źródło
Z jakiegoś powodu kod GUI powoduje, że programiści nie mają pewności co do rozdzielenia problemów. Może dlatego, że wszystkie samouczki grupują wszystko w jedną klasę. Może dlatego, że fizyczna reprezentacja sprawia, że rzeczy wydają się ściślej powiązane niż są. Może dlatego, że klasy budują się powoli, aby ludzie nie rozpoznali, że potrzebują refaktoryzacji, jak przysłowiowa żaba gotowana przez powolne podkręcanie ognia.
Bez względu na przyczynę rozwiązaniem jest, aby Twoje zajęcia były znacznie mniejsze. Robię to, ciągle zadając sobie pytanie, czy można umieścić to, co wpisuję, w osobnej klasie. Jeśli można umieścić w innej klasie i mogę wymyślić rozsądną i prostą nazwę dla tej klasy, robię to.
źródło
Możesz rzucić okiem na wzór Prezenter widoków modelu / Widok pasywny. Ray Ryan wygłosił dobry wykład na temat Google IO na temat najlepszych praktyk architektury dla GWT.
http://www.google.com/events/io/2009/sessions/GoogleWebToolkitBestPractices.html
Łatwo jest wyodrębnić pomysły na inne frameworki i języki. Główną zaletą MVP (moim zdaniem) jest testowanie jednostkowe. I dostajesz to tylko, jeśli twój kod nie jest rozdęty i nie jest spaghetti (sądząc po twoim pytaniu, to jest to, czego chcesz). Działa poprzez wprowadzenie warstwy logiki widoku zwanej prezenterem. Rzeczywisty widok jest od tego oddzielony za pomocą interfejsu (a zatem można go łatwo wyśmiewać w testach jednostkowych). Teraz, ponieważ twoja warstwa logiki widoku (prezenter) jest wolna od wewnętrznych elementów konkretnego interfejsu GUI, możesz zorganizować ją jak zwykły kod i nie jesteś związany np. Z hierarchią dziedziczenia Swings. W idealnym przypadku można przełączać implementacje GUI w różnych ramach, o ile są one zgodne z tym samym interfejsem.
źródło
Moja odpowiedź składa się z czterech części: struktury, prostoty, testowania i składni.
Pierwsze trzy są naprawdę trudne!
Struktura oznacza zwracanie dużej uwagi na użycie najmniejszej ilości kodu i maksymalnej liczby ram, bibliotek itp.
Prostota oznacza utrzymanie prostoty od początkowego projektu do faktycznej implementacji. Pomoże w tym prosta nawigacja, proste wtyczki, przejrzysty układ. Można je teraz „sprzedać” klientom / użytkownikom, którzy mogą szybko zobaczyć zalety stron, które działają na komputerach PC, iPadach, urządzeniach mobilnych i innych urządzeniach.
Testowanie oznacza w tym narzędzia do testowania przeglądarki (webrat i kapibara przychodzą mi do głowy z działaniem szyn), które wychwytują problemy z różnymi przeglądarkami z góry, gdy można zaprojektować lepszy kod, aby poradzić sobie z nimi na początku, w przeciwieństwie do częstego „łatania” kodu przez różnych programistów, ponieważ są „wykrywani” przez użytkowników różnych przeglądarek.
Składnia. Naprawdę pomocne jest użycie kontrolera kodu / IDE / edytora-wtyczki itp. Dla HTML, CSS, JavaScript itp. Korzyść, którą zyskały przeglądarki dzięki możliwości obsługi źle sformułowanego HTML działa przeciwko tobie, gdy różne przeglądarki działają inaczej z to narzędzie niezbędne do sprawdzania formatu HTML. Posiadanie dobrze sformatowanego HTML bardzo pomaga w pozbawionym kodu HTML, ponieważ zły kod powinien mieć lepszą widoczność.
źródło
Rozwiązaniem, które znalazłem, jest kod deklaratywny. Korzystanie z samego kodu proceduralnego to przepis na kod GUI do spaghetti. Jasne, „specjalny sposób na malowanie widżetu” prawdopodobnie pozostanie kodem. Ale to jest kod izolowany w klasie. Programy obsługi zdarzeń, skróty klawiaturowe, rozmiary okien - wszystkie te niechlujne rzeczy najlepiej deklarować.
źródło
Jest tu wiele świetnych odpowiedzi.
Jedną z rzeczy, które pomogły mi uprościć kod GUI, jest upewnienie się, że GUI ma swój własny model danych.
Dla prostego przykładu, jeśli mam GUI z 4 polami wprowadzania tekstu, to mam osobną klasę danych, która przechowuje zawartość tych 4 pól wprowadzania tekstu. Bardziej skomplikowane GUI wymagają więcej klas danych.
GUI projektuję jako model - widok. Model GUI jest kontrolowany przez kontroler aplikacji modelu aplikacji - widok - kontroler. Widok aplikacji jest modelem GUI, a nie samym kodem GUI.
źródło
Aplikacje takie jak edytor tekstu, edytory grafiki itp. Mają złożone interfejsy, a ich kod nie może być prosty. Jednak w przypadku aplikacji biznesowych interfejs GUI nie musi być tak skomplikowany, ale taki, jaki jest nadal.
Niektóre klucze do uproszczenia GUI to (większość dotyczy .NET):
W miarę możliwości dąż do prostszej konstrukcji. Unikaj fantazyjnych zachowań, jeśli firma nie wymaga tego.
Użyj dobrego dostawcy kontroli.
Nie twórz niestandardowej funkcji kontroli w samym kodzie klienta. Zamiast tego utwórz kontrolki użytkownika, które rozszerzają oryginalną kontrolkę w taki sposób, abyś mógł odzwierciedlić swoje specyficzne zachowania w kontrolkach, a nie w kodzie używanego formularza / strony.
Użyj frameworka (nawet domowego) do obsługi internacjonalizacji, zarządzania zasobami, stylów itp., Aby nie powtarzać tego kodu w każdym interfejsie użytkownika.
Do nawigacji użyj komponentu (lub frameworka).
Twórz standardowe dialogi dla błędów, ostrzeżeń, potwierdzeń itp.
źródło
Zastosuj obiektowy projekt do swojego kodu i do tworzenia interfejsu użytkownika:
Oto mała, ale nietrywialna aplikacja, która pomoże zilustrować niektóre z moich argumentów. Kod interakcji między schematem a widokiem / modelem można znaleźć tutaj: https://github.com/vanfrankie/pushpopbox
źródło
Chcesz przyjrzeć się koncepcji „wiązania danych” . W ten sposób łączymy elementy interfejsu użytkownika z abstrakcyjnymi elementami modelu w sposób deklaratywny, dzięki czemu elementy modelu są automatycznie synchronizowane z zawartością interfejsu użytkownika. Podejście to ma wiele zalet, na przykład brak konieczności samodzielnego pisania procedur obsługi zdarzeń w celu synchronizacji danych.
Obsługuje wiązanie danych dla wielu platform interfejsu użytkownika, na przykład .NET i Eclipse / JFace .
źródło