Реализация imho довольно плохая по нескольким причинам:
Шаблон синглтона не реализован должным образом
Шаблон синглтона используется для доступа к экземпляру, содержащему соответствующие данные / функции, через static
, но этот экземпляр должен содержать все соответствующие данные в качестве полей экземпляра.
rootStage
и setUp
равны static
.
Данные хранятся в полях, которые никогданужно снова
Вы никогда не читаете из loadedFxml
или loadedPanes
вне цикла.Вместо этого вы могли бы создать локальные переменные в теле цикла.
Все загружается одновременно
Для нескольких небольших сцен это может не иметь большого значения, но по мере добавления новых и новых сцен это будет увеличиватьсявремя запускаРассмотрим ленивую загрузку сцен.
Данные для сцен хранятся в разных структурах данных
Не большая проблема, но это усложняет обслуживание класса.enum
хранит одну часть данных, используемых для создания / доступа к сценам fxmlFiles
содержит вторую половину.Каждый раз, когда вы добавляете / удаляете сцену, вам нужно обновить обе части вашего кода.В таких случаях было бы предпочтительнее сохранить данные URL в самом перечислении:
public enum States {
MAIN_MENU("../gui/MainWindow.fxml"), NEW_GAME("../gui/NewGameWindow.fxml");
private final url;
States(String url) {
this.url = url;
}
}
for(States state : States.values()) {
FXMLLoader loader = new FXMLLoader(getClass().getResource(state.url));
...
}
Обратите внимание, что вы используете ..
в своих URL, которые перестают работать, если вы упакуетепрограмма как баночка.
Но использование enum
в первую очередь является сомнительным решением.Таким образом, вы не сможете добавлять / удалять сцены без перекомпиляции.
Использование static
не кажется необходимым вообще
Хорошо избегать использования static
ввсе если возможно.(см. Почему статические переменные считаются злыми? ).
Если мое предположение, что вы используете класс SceneManager
только из сцен, загруженных им (и для отображения начальной сцены), правильнонетрудно передать экземпляр SceneManager
в контроллеры сцен, чтобы избежать необходимости использования SceneManager.getInstance
в этих классах (см. Передача параметров JavaFX FXML ):
суперклассдля контроллеров
public class BaseController {
protected SceneManager sceneManager;
void setSceneManager(SceneManager sceneManager) { // if SceneManager and BaseController are in different packages, change visibility
this.sceneManager = sceneManager;
}
}
FXMLLoader loader = ...
Pane pane = loader.load();
BaseController controller = loader.getController();
controller.setSceneManager(this);
Используя URL в качестве идентификаторов для сцен для простоты, вы можете улучшить реализацию:
public class SceneManager {
private final Stage rootStage;
public SceneManager(Stage rootStage) {
if (rootStage == null) {
throw new IllegalArgumentException();
}
this.rootStage = rootStage;
}
private final Map<String, Scene> scenes = new HashMap<>();
public void switchScene(String url) {
Scene scene = scenes.computeIfAbsent(url, u -> {
FXMLLoader loader = new FXMLLoader(getClass().getResource(u));
try {
Pane p = loader.load();
BaseController controller = loader.getController();
controller.setSceneManager(this);
return new Scene(p);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
});
rootStage.setScene(scene);
}
}
Это позволяет вам
- создание разных менеджеров для разных этапов
- загрузка сцен, когда они необходимы в первую очередь
- динамическое добавление дополнительных сцен
- предотвращает состояние, в котором вызывается
switchScene
, ноэтап null
- упрощает доступ к
SceneManager
в классах контроллера до sceneManager.switchScene
SceneManager
, возможно, доступного для сборки мусора до завершения программы, поскольку существуетнет статической ссылки на него.