Fajnie że użyłeś JavaFX, zamiast przestarzałego Swinga, a tak zwykle robi dużo osób tutaj. Niefajnie jednak, że robisz to wszystko tak jak w Swingu. Powinieneś stworzyć plik widoku w JavaFX Scene Builder i dodać do niego kontroler. Wtedy pozbył byś się kilku problemów:
- Tabela, skoro jest dość mocno scustomizowana, powinna być osobną klasą, tak jak ExceptionAlert.
- Klasa Buttons wypadła by całkowicie (bardzo brzydki byt).
Oczywiście tym sposobem też się da, tylko będzie trudniej. Jeżeli się uczysz, to nawet proponuję Ci zrobić tą aplikację w sposób jakim zacząłeś, a potem przerobić to na widok + kontroler.
Ok, więc Twoja aplikacja ma 4 główne elementy:
- Okno
- Tablę jako explorer
- Przyciski do nawigacji
- ExceptionAlert do wypadków
ExceptionAlert ma dość specyficzne zadanie. Zostało wyciągnięte do osobnej klasy żebyś mógł go łatwo stworzyć. Tutaj jest dobrze.
Pozostały więc przyciski, tabela i okno. Tabela również ma osobne zadanie. Ma wyświetlić zawartość jakiegoś katalogu, obsługiwać dwukliki etc. Nie da się więc stworzyć go jedną linijką i też można wyrzucić to do osobnej klasy. A co gdybyś chciał np, przerobić to na taki ala total commander? Masz klasę - no problemo. Tworzysz drugą instancję, umieszczasz obok pierwszej i masz widok 2 katalogów. A może zakładki? Też nie ma problemu. Każda zakładka niech tworzy sobie swoją instancję. Widzisz o co mi chodzi?
Z przyciskami jest już inaczej. One się niczym specjalnym nie wyróżniają. Takie przyciski spotkamy w każdym programie. Posiadają 2 cechy. Napis i czynność do wykonania po kliknięciu. W javie, są 2 zmienne, bo czynność to nic innego jak funkcja. Dlatego przycisków nie ma sensu wywalać do osobnej klasy. Te oryginalne wystarczą.
Okno natomiast, to jest to wszytko razem złączone do kupy.
I teraz przypiszmy te właściwości do obiektów. Jeżeli wrzucisz stos do okna, to będziesz mógł się do niego odnieść z każdego miejsca. Ale co w przypadku gdy pojawi się 10 dodatkowych tabel? Przecież nie będziesz tworzył 10 dodatkowych stosów w oknie. Czyli stos czy currentPath to właściwiość właśnie tabeli. To ona wie w którym miejscu obecnie jest i w jakich miejscach była wcześniej. Powinna udostępnić metody getCurrentPath, goToPath czy goBack i goNext, ale samo zarządzanie stosem nie powinno być dostępne z zewnątrz. Do tego operacje tworzenia katalogu i usuwania też można wyrzucić do osobnej klasy, bo przecież nie jest to typowa obsługa okna.
Jeżeli kiedyś np. będziesz chciał dodać ostrzeżenie przy usuwaniu ("czy na pewno chcesz usunąć ten plik"), to nie mieszasz w oknie, tylko w obiekcie który manipuluje plikami i katalogami.
I tak np. głowne okno tworzy tabelę i 4 przyciski.
- back - wywołuje goBack na tabeli
- up - wywołuje goUp na tabeli
- createDirectory - tworzy obiekt DirectoryManipulator i wywołuje na nim createDirectory(table.getCurrentPath())
- delete - tworzy obiekt DirectoryManipulator i wywołuje na nim delete(table.getSelectedPath).
W ten sposób dojdą 2 nowe klasy specjalistyczne, a kod okna zmniejszy się do potrzebnego minimum.
Na sam koniec pewna uwaga. Nigdy nie stosuj @SuppressWarnings("unchecked")
. Ukrycie ostrzeżeń nie sprawi że twój kod jest lepszy. W ten sposób po prostu olewasz problem, który dalej istnieje. To trochę tak jak ludzie się cieszą że żaden test się nie wywala, bo żadnego nie napisali ;). Jeżeli coś rzuca Ci ostrzeżeniem, to masz 2 wyjścia.
- Poprawić tak, żeby nie rzucało
- Za każdym razem gdy otwierasz plik patrzeć na warning i po n-tym razie gdy mocno się wkur** wrócić do punktu 1 ;).
W ukrywaniu błędów jest jeszcze jedna pułapka. Załóżmy ze coś ukryjesz, ale wiesz czemu tak się dzieje i wiesz że to nie jest żaden problem. Potem możesz coś zmienić w kodzie i niechcący dopisać coś co też rzuci warningiem, ty tego nie zauważysz, a adnotacja pozwoli to zignorować.