加载FXML的两种方式;为什么一个比另一个更受欢迎?
Two ways to load FXML; why is one preferred over the other?
我正在寻找关于为什么我们应该在加载和显示新的 FXML 阶段时使用一种方法而不是另一种方法的反馈。
大多数时候,我会看到教程等显示从单独的 class 完成的阶段加载。但是,它也可以在 FXML 文件的控制器本身内完成,我个人认为这种方式更简洁、更易于管理。
考虑以下 Main.java class:
public class Main extends Application {
@Override
public void start(Stage stage) throws Exception {
// Method 1:
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("Layout.fxml"));
loader.setController(new LayoutController());
stage.setScene(new Scene(loader.load()));
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
这似乎是流行的方法。它创建控制器并设置 Scene
然后显示它。
但是,如果我们将 start()
方法改为:
@Override
public void start(Stage stage) throws Exception {
LayoutController controller = new LayoutController();
controller.showStage();
}
并将 FXML 加载代码移动到 LayoutController
构造函数中,结果是相同的:
public class LayoutController {
@FXML
private Label label;
private Stage stage = new Stage();
public LayoutController() {
// Method 2:
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("Layout.fxml"));
loader.setController(this);
stage.setScene(new Scene(loader.load()));
} catch (IOException e) {
e.printStackTrace();
}
}
public void showStage() {
this.stage.showAndWait();
}
}
我在这里看到的好处是视图和逻辑之间的更多分离。 LayoutController
及其关联的 FXML 文件的所有内容都包含在一个地方。
所以我的问题是:第二种方法有什么问题?我假设它不是标准方法是有原因的,但我看不出有任何缺点。
Would a question like this be more suited to Code Review? I'm not really asking for opinions, as there seems to be a general "rule" that the first method be used.
在这种情况下没有太大区别。
对于较大的程序,第二种方法并不理想:
违反了single responsibility principle:
class负责:
- 创建场景
- 创建舞台
- 显示舞台(更糟糕的是,它以可能干扰其他逻辑的方式执行此操作 (
showAndWait
))
- 它是视图的控制器,可能会负责处理多个事件
此外,class 的设计方式可以防止责任毫无问题地转移到其他 classes。
在较大的程序中,您可能希望创建一个 class 来管理向视图传递数据、安排 windows 或将视图显示为场景的一部分等。第二种方法不适合这种情况。
此外,不重复自己也更难。除非将逻辑移至通用超类型,否则还需要在每个控制器中实现显示场景的逻辑 class。重复相同或相似的代码会导致代码难以维护。
注意: 使用单个 class 加载 fxml 并用作控制器不一定是坏事,但你应该使用 Introduction to FXML.
中介绍的自定义组件方法
我正在寻找关于为什么我们应该在加载和显示新的 FXML 阶段时使用一种方法而不是另一种方法的反馈。
大多数时候,我会看到教程等显示从单独的 class 完成的阶段加载。但是,它也可以在 FXML 文件的控制器本身内完成,我个人认为这种方式更简洁、更易于管理。
考虑以下 Main.java class:
public class Main extends Application {
@Override
public void start(Stage stage) throws Exception {
// Method 1:
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("Layout.fxml"));
loader.setController(new LayoutController());
stage.setScene(new Scene(loader.load()));
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
这似乎是流行的方法。它创建控制器并设置 Scene
然后显示它。
但是,如果我们将 start()
方法改为:
@Override
public void start(Stage stage) throws Exception {
LayoutController controller = new LayoutController();
controller.showStage();
}
并将 FXML 加载代码移动到 LayoutController
构造函数中,结果是相同的:
public class LayoutController {
@FXML
private Label label;
private Stage stage = new Stage();
public LayoutController() {
// Method 2:
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("Layout.fxml"));
loader.setController(this);
stage.setScene(new Scene(loader.load()));
} catch (IOException e) {
e.printStackTrace();
}
}
public void showStage() {
this.stage.showAndWait();
}
}
我在这里看到的好处是视图和逻辑之间的更多分离。 LayoutController
及其关联的 FXML 文件的所有内容都包含在一个地方。
所以我的问题是:第二种方法有什么问题?我假设它不是标准方法是有原因的,但我看不出有任何缺点。
Would a question like this be more suited to Code Review? I'm not really asking for opinions, as there seems to be a general "rule" that the first method be used.
在这种情况下没有太大区别。
对于较大的程序,第二种方法并不理想:
违反了single responsibility principle:
class负责:
- 创建场景
- 创建舞台
- 显示舞台(更糟糕的是,它以可能干扰其他逻辑的方式执行此操作 (
showAndWait
)) - 它是视图的控制器,可能会负责处理多个事件
此外,class 的设计方式可以防止责任毫无问题地转移到其他 classes。
在较大的程序中,您可能希望创建一个 class 来管理向视图传递数据、安排 windows 或将视图显示为场景的一部分等。第二种方法不适合这种情况。
此外,不重复自己也更难。除非将逻辑移至通用超类型,否则还需要在每个控制器中实现显示场景的逻辑 class。重复相同或相似的代码会导致代码难以维护。
注意: 使用单个 class 加载 fxml 并用作控制器不一定是坏事,但你应该使用 Introduction to FXML.
中介绍的自定义组件方法