Model view controller JavaFX(ML)中是否可以使用单例控制器?

Model view controller JavaFX(ML)中是否可以使用单例控制器?,model-view-controller,javafx,singleton,Model View Controller,Javafx,Singleton,我尝试用singleton模式实现一个控制器,就像在web上描述过的几次一样 但是,由于以下异常,我无法运行应用程序 java.lang.IllegalAccessException: Class sun.reflect.misc.ReflectUtil can not access a member of class testapp.Controller with modifiers "private" 我猜这是因为构造函数被声明为私有的。我看不出我在这一点上做错了什么 如果我不清楚我的问题

我尝试用singleton模式实现一个控制器,就像在web上描述过的几次一样

但是,由于以下异常,我无法运行应用程序

java.lang.IllegalAccessException: Class sun.reflect.misc.ReflectUtil can not access a member of class testapp.Controller with modifiers "private"
我猜这是因为构造函数被声明为私有的。我看不出我在这一点上做错了什么

如果我不清楚我的问题是什么,我将描述我将要做的事情的用例

start(Stage)
函数中,afaik是唯一可以定义onclose事件的地方(如果我错了,请纠正我)。关闭窗口时,需要执行一些清理操作。这些操作在控制器内部,我无法在
start()函数中访问这些操作。因此,我们的想法是将控制器构建为一个单独的实例,以保持一个单独的实例处于活动状态,并提供对主类的访问


sillyfly建议的链接对我来说似乎不是一个可能的解决方案,因为控制器被传递给模型类而不是主类。另外,手动调用模型构造函数,这不是我要处理的情况

要解决你的问题,你有两种可能。您可以向自己实例化的FXML加载程序提供singleton控制器的实例 或者为FXML加载程序提供一个控制器工厂,该工厂知道如何实例化控制器。
要解决您的问题,您有两种可能。您可以向自己实例化的FXML加载程序提供singleton控制器的实例 或者为FXML加载程序提供一个控制器工厂,该工厂知道如何实例化控制器。

这对我来说就像是一个笑话

(对我来说)把一个控制器变成一个单体是没有意义的。实际上,每个JavaFX控制器都是有状态的,需要对视图状态进行一些访问:在某个时候,您需要检查文本字段中的文本,或组合框中的选定项,等等,因此您需要对视图的元素(文本字段或组合框等)进行引用。因此,在实践中,控制器实例和FXML文件定义的层次结构实例之间需要有1-1对应关系。因此,如果将控制器设为单例,则只能加载FXML文件一次

问题是,没有办法强制(在与singleton工作相同的强制级别上)“只加载此FXML文件一次”。因此,您必须仅通过编程逻辑来执行此规则。当然,一旦你这样做了,你的编程逻辑现在强制你无论如何只有一个控制器实例,所以你有效地实现了同样的事情。如果您通过编程逻辑来实现这一点,它允许您在以后需要时重用控制器FXML视图对;将控制器类设为单例可以防止这种情况发生,尽管从应用程序代码中看不出这种情况。因此,将控制器设置为单例可以减少重用(在返回代码时,这种方式不会明显),但不会提供额外的好处

您在问题中的状态是您“需要”这样做,因为您需要访问主阶段的
onClose
处理程序中的控制器。我不明白为什么您不能以通常的方式访问控制器:

@Override
public void start(Stage primaryStage) throws IOException {

    FXMLLoader loader = new FXMLLoader(getClass().getResource("/path/to/fxml/file.fxml"));
    Parent root = loader.load();
    Scene scene = new Scene(root);
    primaryStage.setScene(scene);

    MyControllerClass controller = loader.getController();
    primaryStage.setOnHidden(e -> {
        // do clean-up:
        controller.shutdown();

        // ...
    });

    primaryStage.show();
}
即使将加载FXML委托给其他类,也必须在
start
方法(及其对主阶段的引用)和加载
FXML
的方法之间定义一些路由,因此,您有一个路径,可以通过该路径传递stage引用或controller引用来实现您所需的功能。

这对我来说就像是一个问题

(对我来说)把一个控制器变成一个单体是没有意义的。实际上,每个JavaFX控制器都是有状态的,需要对视图状态进行一些访问:在某个时候,您需要检查文本字段中的文本,或组合框中的选定项,等等,因此您需要对视图的元素(文本字段或组合框等)进行引用。因此,在实践中,控制器实例和FXML文件定义的层次结构实例之间需要有1-1对应关系。因此,如果将控制器设为单例,则只能加载FXML文件一次

问题是,没有办法强制(在与singleton工作相同的强制级别上)“只加载此FXML文件一次”。因此,您必须仅通过编程逻辑来执行此规则。当然,一旦你这样做了,你的编程逻辑现在强制你无论如何只有一个控制器实例,所以你有效地实现了同样的事情。如果您通过编程逻辑来实现这一点,它允许您在以后需要时重用控制器FXML视图对;将控制器类设为单例可以防止这种情况发生,尽管从应用程序代码中看不出这种情况。因此,将控制器设置为单例可以减少重用(在返回代码时,这种方式不会明显),但不会提供额外的好处

您在问题中的状态是您“需要”这样做,因为您需要访问主阶段的
onClose
处理程序中的控制器。我不明白为什么您不能以通常的方式访问控制器:

@Override
public void start(Stage primaryStage) throws IOException {

    FXMLLoader loader = new FXMLLoader(getClass().getResource("/path/to/fxml/file.fxml"));
    Parent root = loader.load();
    Scene scene = new Scene(root);
    primaryStage.setScene(scene);

    MyControllerClass controller = loader.getController();
    primaryStage.setOnHidden(e -> {
        // do clean-up:
        controller.shutdown();

        // ...
    });

    primaryStage.show();
}
即使将加载FXML委托给其他类,也必须在
start
方法(及其对主阶段的引用)和加载
FXML
的方法之间定义一些路由,因此,您有一条路径,通过该路径,您可以传递stage引用或controller引用以实现所需的功能。

在其他类中:

@FXML
private void btnIngresarOnAction() {
    try {
        FXMLLoader fxmlLoader = new FXMLLoader();
        fxmlLoader.setLocation(getClass().getResource("/fxml/Frame.fxml"));
        Parent rootNode = fxmlLoader.load();
        Stage stage = new Stage();
        stage.setTitle("Frame");
        Scene scene = new Scene(rootNode);
        stage.setOnCloseRequest(event -> FrameController.frame = null);
        stage.setScene(scene);
        stage.show();
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
}
课堂独生子女:

@Lazy
@Component
public class FrameController implements Initializable {

    public static FrameController frame;

    public FrameController() {
        if (frame == null) {
            frame = this;
        } else {
            throw new RuntimeException("Singleton FXML");
        }
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        System.out.println("Initialize");
    }
}
在其他类别中:

@FXML
private void btnIngresarOnAction() {
    try {
        FXMLLoader fxmlLoader = new FXMLLoader();
        fxmlLoader.setLocation(getClass().getResource("/fxml/Frame.fxml"));
        Parent rootNode = fxmlLoader.load();
        Stage stage = new Stage();
        stage.setTitle("Frame");
        Scene scene = new Scene(rootNode);
        stage.setOnCloseRequest(event -> FrameController.frame = null);
        stage.setScene(scene);
        stage.show();
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
}
课堂独生子女:

@Lazy
@Component
public class FrameController implements Initializable {

    public static FrameController frame;

    public FrameController() {
        if (frame == null) {
            frame = this;
        } else {
            throw new RuntimeException("Singleton FXML");
        }
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        System.out.println("Initialize");
    }
}

我不能使用这种方法,因为我需要主类中的控制器实例在oncl中使用它