替代Java中的单例模式,而不是依赖注入或观察者

时间:2016-09-12 07:08:07

标签: java javafx dependency-injection singleton observer-pattern

我正在制作一个JavaFX应用程序,它有四个根控制器。其中每个控制选项卡上的视图。选项卡选择器没有控制器,因为它没有选择要显示的四个视图中的哪一个的功能。这些控制器需要访问相同的数据,并且都可以修改这些数据。

我能看到以可读方式实现此目的的唯一方法是使用静态单例存储可由所有四个控制器访问和修改的状态。出于显而易见的原因,这并不理想。

我无法使用依赖注入,因为在启动应用程序时会初始化所有控制器,它们不会彼此创建。出于同样的原因,我无法使用观察者模式。他们无法相互获得参考,因此他们无法相互观察。据我所知,Java中没有广播通知系统很烦人,因为它是一个解决方案。是否有我可以使用的其他模式或某种方式我可以使这些模式之一工作?

选项卡的fxml文件作为内容添加到选项卡窗格中。这样做是为了让每个标签都有一个不同的控制器。然后,start方法加载选项卡窗格fxml。

<TabPane prefHeight="200.0" prefWidth="200.0"   tabClosingPolicy="UNAVAILABLE" BorderPane.alignment="CENTER">
        <tabs>
          <Tab text="Data &amp; Statistics">
            <content>
              <fx:include fx:id="dataViewTabControl" source="DataViewTabControl.fxml" />
            </content>
          </Tab>
            . . .

1 个答案:

答案 0 :(得分:2)

您可以通过在FXMLLoader上设置控制器工厂来有效地使用依赖注入。这允许您控制如何为指定控制器类fx:controller属性的FXML文件创建控制器实例。控制器工厂用于包含FXML文件以及主FXML文件。

因此,您可以使用应用程序状态创建模型类,从控制器中观察和修改该状态,并创建在所有控制器之间共享的单个实例。

定义您的模型:

public class Model { /* ... */ }

因此,如果使用控制器定义DataViewTabControl.fxml文件,例如:

<?xml version="1.0" encoding="UTF-8"?>

<!-- imports etc -->

<SomeRootPane fx:controller="com.example.DataViewTabController">

    <!-- ... -->

</SomeRootPane>

并定义您的DataViewTabController以在构造函数中获取Model参数:

public class DataViewTabController {

    private final Model model ;

    public DataViewTabController(Model model) {
        this.model = model ;
    }

}

现在,当您加载主FXML文件以及可能具有将模型作为构造函数参数的控制器或执行相同操作的<fx:include>的任何其他文件时,请使用调用正确构造函数的控制器工厂:

Model model = new Model();

FXMLLoader loader = new FXMLLoader(getClass().getResource("/path/to/fxml/file"));

loader.setControllerFactory((Class<?> controllerType) -> {
    try {
        for (Constructor<?> con : controllerType.getConstructors()) {
            if (con.getParameterCount() == 1 && con.getParameterTypes()[0]==Model.class) {
                return con.newInstance(model);
            }
        }
        // no suitable constructor found: just return default instance
        return controllerType.newInstance();
    } catch (Exception e) {
        System.err.println("Warning: could not load controller");
        e.printStackTrace(System.err);
        return null ;
    }
});

现在所有控制器都可以访问相同的Model实例,因此您可以使用通常的MVC / Observer模式来更改数据并响应数据更改。如果您的模型类使用JavaFX property API

,这一点尤为简单