Dlaczego za najlepszą praktykę uważa się pakowanie kodu programu i kodu interfejsu graficznego w różne klasy?

15

Więc mój nauczyciel mówi mi, że bardzo ważne jest, aby nie kapsułkować kodu programu i kodu interfejsu graficznego w tych samych klasach, ale aby zachować ich całkowitą niezależność. Obecnie piszę grę na iPhone'a z siatką. dla mnie sensowniej jest stworzyć zarówno graficzną siatkę, jak i kod techniczny w tej samej klasie „Siatka”. Czy inny programista się na to zgodzi? Czy to naprawdę bardzo ważne, aby interfejs graficzny i kod były niezależne. Jakie problemy pojawią się, jeśli tego nie zrobię?

Dziękuję Ci!

EDYCJA: dzięki chłopaki! Czy byłoby dla mnie w porządku, aby najpierw napisać projekt, a następnie skopiować kod, aby stworzyć projekt rozdzielenia problemów? Wiem, że może to całkowicie pokonać cel, ale podobnie jak praktyka ... Więc następnym razem mogę zastosować ten wzór projektowy od samego początku?

Jan
źródło

Odpowiedzi:

17

Pojęcie, do którego odnosi się twój nauczyciel, nazywa się oddzieleniem obaw.

Aby zilustrować to w swoim kontekście, jeśli ukończyłeś program, a następnie zdecydowałeś, że chcesz go przenieść na Androida; będziesz musiał ponownie napisać dużo więcej kodu, niż gdybyś oddzielił logikę siatki.

Kontrola interfejsu powinna zajmować się tylko rysowaniem tego, co zostało powiedziane, logika siatki powinna dotyczyć tylko tego, co jest w siatce, a nie sposobu jej rysowania.

Czy to pomaga ?

Russ Clarke
źródło
Dzięki, pomogło. Chodzi o to, że dużo łatwiej jest mi wizualizować mój końcowy produkt, kiedy podsumowuję oba w klasie. Czy to jest dla mnie uzasadniony powód, by nie stosować się do „rozdzielenia obaw”? A może jest to absolutnie konieczne i nie mogę nazwać się właściwym programistą: p?
Pozytywnym efektem tego rozdzielenia jest to, że nie musisz przepisywać logiki gry, jeśli na przykład zdecydujesz się zastąpić GUI
@John - Napisz dokument specyfikacji, jeśli potrzebujesz wizualizować swój projekt. Jeśli potrafisz to opisać, możesz zacząć oddzielać kod interfejsu graficznego od samej logiki gry.
Ramhound
3
Ułatwia także testowanie kodu siatki. Testowanie GUI jest bolesne (z powodu możliwych problemów ze środowiskiem), więc uzyskanie GUI jest cienką „oczywiście poprawną” warstwą nad czymś, co można przetestować, jest ogromną wygraną. (Ponownie jest to oddzielenie obaw).
Donal Fellows
1
@John: Niektórzy z nas uczą się najlepiej, robiąc. Zakładając, że ten projekt nie jest tak duży, spróbuj napisać go jako pojedynczą klasę i uruchom go na iPhonie. Teraz przenieś go na Androida, śledząc swoje „punkty bólu”. Na koniec przepisz, jak sugerował Russ C. Myślę, że zrozumiesz, dlaczego separacja logiki i prezentacji jest najlepszym rozwiązaniem.
Peter Rowell,
4

Aby ułatwić zmianę kodu . Co jeśli jutro nie chcesz używać siatki, ale listy? Kiedy GUI jest oddzielone od logiki, jest to łatwe do zrobienia.

Poza tym napiszesz kod, który jest bardziej wielokrotnego użytku . Jeśli twój GUI nie zawiera twojego kodu technicznego, możesz go ponownie użyć. Utwórz jednorazową fantazyjną siatkę ze wszystkimi opcjami, aby móc jej używać w innych projektach. Pomieszanie GUI i kodu technicznego uniemożliwi ci to.

Daje również kod, który jest łatwiejszy do odczytania. Jeśli twoja siatka obsługuje tylko GUI, łatwiej jest zrozumieć lub zmienić kod.

Carra
źródło
3

Ogólne podejście programowania obiektowego do rozdzielania problemów , w których kod dzieli się na logiczne zadania. Początkowo może to wydawać się więcej pracy. Ale wraz z rozwojem projektu łatwiej jest śledzić kod i zarządzać nim.

Z tego powodu lepiej byłoby oddzielić kod odpowiedzialny za wyświetlanie siatki i kod, który zajmuje się danymi, które mogą być wyświetlane w tej siatce.

Jonathan Wood
źródło
0

Aby oprzeć się na innych odpowiedziach i dać przykład, powinieneś w jakiś sposób pozwolić sobie na wstrzyknięcie logiki / danych do sieci lub odwrotnie.

Kontrolka siatki może ujawnić Rendermetodę lub DataBindmetodę.

class GridControl
{
    public Render(GridData data) { ... }
}

lub

class GridControl
{
    public DataBind(GridData data) { ... }
}

Następnie jednostka logiczna może albo przejąć GridControl i powiązać z nim obiekt danych, albo ręcznie wywołać renderowanie z obiektem danych za każdym razem, gdy coś się zmieni.

Twój GridLogic powinien również zawierać odwołanie do GridControl, aby mógł się wiązać z każdym zdarzeniem wejściowym / zdarzeniem.

Idea powiązania danych polega na tym, że kontrolka siatki śledzi dane pod kątem wszelkich zmian i renderuje się ponownie, gdy ujawnienie funkcji renderowania oznacza, że ​​jednostka logiczna ręcznie renderuje kontrolę.

Tak czy inaczej podzielenie logiki i siatki w ten sposób pozwala na łatwiejszą zmianę jednej z nich bez niszczenia niczego. Możesz także napisać nowy element sterujący, taki jak a, ListControlaby wyświetlać dane jako listę zamiast siatki bez konieczności przepisywania całej logiki.

Raynos
źródło
0

Zdecydowanie polecam przyjrzeć się architekturze MVC .

Jest to udoskonalenie wspomnianej koncepcji (oddzielenie kodu programu i interfejsu graficznego). MVC oznacza Model-View-Controller. Tutaj model to dane, widok to kod interfejsu graficznego, a kontroler to kod przetwarzający dane.

W ten sposób stworzyłeś trzy części swojego programu. Każda część może zostać wymieniona bez konieczności zmiany pozostałych dwóch części.

DPD
źródło
0

To zależy od rodzaju przyszłych zmian, których możesz się spodziewać. To, co chcesz zminimalizować, to liczba ręcznych zmian kodu potrzebnych do prawidłowego wdrożenia każdej pojedynczej zmiany funkcjonalnej.

MVC wygrywa, jeśli zmiany ograniczają się do części V lub „Widok”.

Z mojego doświadczenia wynika, że jest znacznie bardziej prawdopodobne, że zmiany dotyczą wszystkich trzech części, więc lepiej jest, jeśli są one nie rozdzielono. Aby pokazać, co mam na myśli, od dawna korzystam z opracowanej przeze mnie techniki o nazwie Dynamic Dialogs , w której nowe wymaganie, takie jak „zezwól użytkownikowi na edycję nazwy i po zakończeniu do XYZ” jest wprowadzane do kodu źródłowego jako pojedynczy blok tekst:

if(deTextEdit(&sName)){
  // do XYZ
}

zamiast wielu oddzielnych edycji, aby określić, że pole edycyjne istnieje, aby utworzyć dla niego unikalny identyfikator, powiązać go ze zmienną modelu i połączyć z modułem obsługi zdarzeń Lost-Focus.

Jeśli przejdziesz do tego linku, zobaczysz bardziej złożony przykład.

Zasadniczo chodzi o przekształcenie kodu w język specyficzny dla domeny, aby zminimalizować liczbę edycji potrzebnych do osiągnięcia tego celu. Powodem, dla którego chcesz to zrobić, jest nie tylko zmniejszenie wysiłku, ale także ograniczenie możliwości wprowadzania błędów, poprzez zapomnienie lub błędne kodowanie jednej lub więcej zmian. Zmniejsza to również rozmiar kodu źródłowego o około rząd wielkości.

To nie jest za darmo. Wprowadza jednorazową krzywą uczenia się dla programisty.

Mike Dunlavey
źródło
0

Interfejs graficzny jest zależny od systemu, podczas gdy rdzeń gry jest algorytmem całkowicie niezależnym od systemu, na którym działa. Utrzymanie tych dwóch aplikacji ułatwi utrzymanie, testowanie i debugowanie programu, ponieważ zmiany w jednym podsystemie nie wpływają na sposób działania drugiego. Nawet jeśli nie zależy Ci na przenośności, założę się, że zależy Ci na niezawodności i łatwości konserwacji twojego programu.

Gus
źródło