在JavaFx中处理和扩展Node的正确方法 [英] The correct way to handle and extend Node in JavaFx

查看:31
本文介绍了在JavaFx中处理和扩展Node的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在寻求更好的编码实践的过程中,我遇到了一个我已经从事很长时间的编码想法,甚至我看到该站点的程序员(我认为是专家)都使用相同的编码想法.

In my quest to have better coding practices, I have come across a coding idea that I have been doing for a long time and I even see programmers from this site, who I consider experts, use the same coding idea.

例如,在下面的代码中,我扩展了Pane.为了得到班级的孩子,在这种情况下,我总是打电话给 this.getChildren().今天,我注意到Netbeans发出了警告消息,因此我查找了一下,发现要摆脱该警告,我应该使用 super.getChildren().是我以后应该处理这种情况的推荐方法,还是 this.getChildren()一样好?

For example in the code below I extend Pane. To get the class' children I have always called this.getChildren() in this situation. Today I noticed Netbeans gives a warning message, so I looked it up and found that to get rid of the warning I should use super.getChildren(). Is the recommend way I should handle this situation in the future or is this.getChildren() just as good?

public class FlashCard extends Pane
{    
    FlashCard(int num1, int num2, int answer)
    {

        Label lblNum1 = new Label(Integer.toString(num1));
        Label lblNum2 = new Label(Integer.toString(num2));
        Label lblAnswer = new Label(Integer.toString(answer));

        VBox vbox = new VBox();
        vbox.getChildren().addAll(lblNum1, lblNum2, lblAnswer);          
        super.getChildren().add(vbox);
    }
}

推荐答案

这是Josh Bloch的有效Java" (第二版)中的第17项:为继承进行设计和文档,否则禁止使用它".(如果您还没有的话,我强烈建议您阅读这本书.)特别是:

This is Item 17 from Josh Bloch's "Effective Java" (Second Edition): "Design and document for inheritance or else prohibit it". (I strongly recommend reading this book, if you haven't already.) Specifically:

一个类还必须遵守一些其他限制才能允许继承.构造函数不得调用可重写的方法.

基本问题是,如果要子类化 FlashCard 并重写 getChildren()的方式取决于子类构造函数中执行的初始化,则代码将中断. FlashCard 构造函数将在子类构造函数之前被调用,因此它将在初始化发生之前调用 getChildren() .在一个人为的例子中:

The basic problem is that if you were to subclass FlashCard and override getChildren() in a way that depended on initialization performed in the subclass constructor, your code would break. The FlashCard constructor would be invoked before the subclass constructor, so it would invoke getChildren() before the initialization had taken place. In a somewhat artificial example:

public class SpecialFlashCard extends FlashCard {

    private ObservableList<Node> subclassChildren ;

    public SpecialFlashCard(int num1, int num2, int answer) {
        super(num1, num2, answer);
        subclassChildren = FXCollections.observableArrayList();
    }

    @Override
    public ObservableList<Node> getChildren() {
        return subclassChildren ;
    }
}

如果 FlashCard 构造函数调用了 this.getChildren(),则调用子类构造函数将抛出 NullPointerException ,因为超类构造函数将尝试在 subclassChildren 中添加元素,然后再对其进行初始化.另一方面,如果 FlashCard 构造函数调用了 super.getChildren(),则子类将无法按预期方式运行(因为 getChildren()将返回不包含标签的列表.

If the FlashCard constructor invoked this.getChildren(), then invoking the subclass constructor would throw a NullPointerException, because the superclass constructor would attempt to add elements to subclassChildren before it was initialized. On the other hand, if the FlashCard constructor invoked super.getChildren(), then the subclass would not behave as expected (because getChildren() would return a list that did not include the labels).

这里最简单的方法要么是禁止对 FlashCard 进行子类化,要么首先避免对 Pane 进行子类化.

The simplest approaches here are either to prohibit subclassing of FlashCard or to avoid subclassing Pane in the first place.

要禁止子类化,请使 FlashCard 为最终版本:

To prohibit subclassing, make FlashCard final:

public final class FlashCard extends Pane {

    public FlashCard(int num1, int num2, int answer) {

        Label lblNum1 = new Label(Integer.toString(num1));
        Label lblNum2 = new Label(Integer.toString(num2));
        Label lblAnswer = new Label(Integer.toString(answer));

        VBox vbox = new VBox();
        vbox.getChildren().addAll(lblNum1, lblNum2, lblAnswer);          
        this.getChildren().add(vbox);
    }
}

这完全避免了该问题,因为现在您不能继承 FlashCard 的子类,因此无法覆盖其 getChildren()方法(您不再从中调用可重写的方法构造函数).

This completely avoids the problem, because now you cannot subclass FlashCard, and so you cannot override its getChildren() method (you are no longer calling an overridable method from the constructor).

另一种方法(我倾向于使用)不是首先将 Pane 子类化.这是 Effective Java 中的第16项:从喜好到继承".

An alternative approach (which I tend to prefer), is not to subclass Pane in the first place. This is Item 16 from Effective Java: "Favor composition over inheritance".

public class FlashCard {

    private final Pane pane ;

    public FlashCard(int num1, int num2, int answer) {
        Label lblNum1 = new Label(Integer.toString(num1));
        Label lblNum2 = new Label(Integer.toString(num2));
        Label lblAnswer = new Label(Integer.toString(answer));

        VBox vbox = new VBox();
        vbox.getChildren().addAll(lblNum1, lblNum2, lblAnswer); 

        this.pane = new Pane();         
        this.pane.getChildren().add(vbox);
    }

    public Pane asPane() {
        return pane ;
    }
}

(请注意,构造函数不会调用任何可重写的方法.)

(Note that the constructor does not invoke any overridable methods.)

这允许与您现有的 FlashCard 类基本相同的功能,但API稍有修改.例如.代替

This allows essentially the same functionality as your existing FlashCard class, but with a slightly modified API. E.g. instead of

FlashCard flashCard = new FlashCard(6, 9, 42);
someContainer.getChildren().add(flashCard);

你做

FlashCard flashCard = new FlashCard(6, 9, 42);
someContainer.getChildren().add(flashCard.asPane());

这篇关于在JavaFx中处理和扩展Node的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆