class Javafx 的静态实例
Static instances of class Javafx
我有一个 main class,其中包含 main 方法和 start 方法。现在我还有很多其他 classes。例如,我有一个登录 class、注册 class 等等。我有一个 class 只处理当前登录用户的数据。 class 需要从很多控制器访问。因为这个用户总是只有一个,所以 class 的一个实例。我想知道什么是最好的方法,这样每个 class 都可以访问它更新它。
我目前正在应用的是在我的主 class 中创建一个记录用户数据类型 class 的静态实例。然后访问它们。
public static loggedUserData user = new loggedUserData();
然后从任何地方访问它:
demo.user.set(...);
虽然 class 方法和字段是非静态的。我认为可能有更好的方法来解决这个问题。
您的 user
对象是在 MVC/MVP 等设计中构成模型一部分的应用程序数据:
package application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
public class DataModel {
private ObjectProperty<User> currentUser = new SimpleObjectProperty<>();
public final ObjectProperty<User> currentUserProperty() {
return this.currentUser;
}
public final User getCurrentUser() {
return this.currentUserProperty().get();
}
public final void setCurrentUser(final User currentUser) {
this.currentUserProperty().set(currentUser);
}
// other properties, etc...
}
在相对简单的应用程序中,我创建了一个引用模型实例的单例 controller factory 并将其传递给可以接受它的任何控制器构造函数:
package application;
import java.lang.reflect.Constructor;
import javafx.util.Callback;
public enum ControllerFactory implements Callback<Class<?>, Object> {
INSTANCE ;
private final DataModel model = new DataModel();
@Override
public Object call(Class<?> type) {
try {
for (Constructor<?> constructor : type.getConstructors()) {
if (constructor.getParameterCount() == 1
&& DataModel.class.isAssignableFrom(constructor.getParameterTypes()[0])) {
return constructor.newInstance(model);
}
}
return type.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
(另一种选择,而不是在这里使用单例模式,只是有一个接受 DataModel
的构造函数,并注意始终传递对同一个 DataModel
实例的引用。通常这样做是很自然的。)
然后你可以拥有看起来像
的控制器
package application;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
public class LoginController {
private final DataModel model ;
@FXML
private TextField userNameTextField ;
public LoginController(DataModel model) {
this.model = model ;
}
@FXML
private void login() {
model.setCurrentUser(new User(userNameTextField.getText()));
}
}
和
package application;
import javafx.beans.binding.Bindings;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class SomeOtherController {
private final DataModel model ;
@FXML
private Label userLabel ;
public SomeOtherController(DataModel model) {
this.model = model ;
}
public void initialize() {
// Use EasyBind https://github.com/TomasMikula/EasyBind for
// more robust binding to a "property of a property"
userLabel.textProperty().bind(Bindings.select(model.currentUserProperty(), "userName"));
}
}
如果您使用以下习惯用法加载您的 FXML 文件,控制器将自动填充(共享)数据模型:
package application;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws IOException {
String resource = "Login.fxml" ;
FXMLLoader loader = new FXMLLoader(getClass().getResource(resource));
loader.setControllerFactory(ControllerFactory.INSTANCE);
Parent root = loader.load();
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
对于更复杂的应用程序(或者如果您更喜欢 convention-based/opinionated 方法),请考虑使用专用的 JavaFX 依赖注入框架,例如 Afterburner.fx.
我有一个 main class,其中包含 main 方法和 start 方法。现在我还有很多其他 classes。例如,我有一个登录 class、注册 class 等等。我有一个 class 只处理当前登录用户的数据。 class 需要从很多控制器访问。因为这个用户总是只有一个,所以 class 的一个实例。我想知道什么是最好的方法,这样每个 class 都可以访问它更新它。
我目前正在应用的是在我的主 class 中创建一个记录用户数据类型 class 的静态实例。然后访问它们。
public static loggedUserData user = new loggedUserData();
然后从任何地方访问它:
demo.user.set(...);
虽然 class 方法和字段是非静态的。我认为可能有更好的方法来解决这个问题。
您的 user
对象是在 MVC/MVP 等设计中构成模型一部分的应用程序数据:
package application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
public class DataModel {
private ObjectProperty<User> currentUser = new SimpleObjectProperty<>();
public final ObjectProperty<User> currentUserProperty() {
return this.currentUser;
}
public final User getCurrentUser() {
return this.currentUserProperty().get();
}
public final void setCurrentUser(final User currentUser) {
this.currentUserProperty().set(currentUser);
}
// other properties, etc...
}
在相对简单的应用程序中,我创建了一个引用模型实例的单例 controller factory 并将其传递给可以接受它的任何控制器构造函数:
package application;
import java.lang.reflect.Constructor;
import javafx.util.Callback;
public enum ControllerFactory implements Callback<Class<?>, Object> {
INSTANCE ;
private final DataModel model = new DataModel();
@Override
public Object call(Class<?> type) {
try {
for (Constructor<?> constructor : type.getConstructors()) {
if (constructor.getParameterCount() == 1
&& DataModel.class.isAssignableFrom(constructor.getParameterTypes()[0])) {
return constructor.newInstance(model);
}
}
return type.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
(另一种选择,而不是在这里使用单例模式,只是有一个接受 DataModel
的构造函数,并注意始终传递对同一个 DataModel
实例的引用。通常这样做是很自然的。)
然后你可以拥有看起来像
的控制器package application;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
public class LoginController {
private final DataModel model ;
@FXML
private TextField userNameTextField ;
public LoginController(DataModel model) {
this.model = model ;
}
@FXML
private void login() {
model.setCurrentUser(new User(userNameTextField.getText()));
}
}
和
package application;
import javafx.beans.binding.Bindings;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class SomeOtherController {
private final DataModel model ;
@FXML
private Label userLabel ;
public SomeOtherController(DataModel model) {
this.model = model ;
}
public void initialize() {
// Use EasyBind https://github.com/TomasMikula/EasyBind for
// more robust binding to a "property of a property"
userLabel.textProperty().bind(Bindings.select(model.currentUserProperty(), "userName"));
}
}
如果您使用以下习惯用法加载您的 FXML 文件,控制器将自动填充(共享)数据模型:
package application;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws IOException {
String resource = "Login.fxml" ;
FXMLLoader loader = new FXMLLoader(getClass().getResource(resource));
loader.setControllerFactory(ControllerFactory.INSTANCE);
Parent root = loader.load();
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
对于更复杂的应用程序(或者如果您更喜欢 convention-based/opinionated 方法),请考虑使用专用的 JavaFX 依赖注入框架,例如 Afterburner.fx.