何时使用 JavaFX 属性 setter 和 getter,而不是直接使用 属性

When to use JavaFX properties setter and getter, instead of using the property directly

我熟悉Java,但刚开始学习JavaFX,具体了解JavaFX属性。我理解基本设计模式,如以下 Oracle 示例所示:

package propertydemo;

import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;

class Bill {

    // Define a variable to store the property
    private DoubleProperty amountDue = new SimpleDoubleProperty();

    // Define a getter for the property's value
    public final double getAmountDue(){return amountDue.get();}

    // Define a setter for the property's value
    public final void setAmountDue(double value){amountDue.set(value);}

     // Define a getter for the property itself
    public DoubleProperty amountDueProperty() {return amountDue;}

}

我不明白的是when/why我会使用getter和setter方法,而不是直接使用属性?

我在想的是,您可能需要 getter and/or setter 中的一些自定义代码,这些代码可能会做一些预或 post manipulation/validation的数据,但是如果您创建自定义 getter and/or setter,那么您会得到不同的结果,具体取决于您使用的是 getter/setter 还是 属性直接,对我来说,这似乎很危险。

如果 getter/setter 只是调用 属性 的 get 和 set 方法,那为什么还要它们?

如有任何见解,我们将不胜感激。

JavaFX 属性 模式旨在扩展旧的标准 JavaBean 模式。因此,在您的示例中,根据 JavaBean 约定,您有一个类型为 double 的(读写)属性,名为 amount。这是由两种方法决定的

public double getAmount() ;
public void setAmount(double amount);

JavaBean 模式允许一些有限的"observability" 通过"bound properties",其中bean 支持注册一个PropertyChangeListener。 UI 工具包通常需要观察属性并响应变化。例如,Labeltext 属性 是有意义的。如果 text 属性 发生变化,则需要通知 Label ,以便它知道重新绘制自己。乍一看,使用具有绑定属性的 JavaBeans 是一种实现此目的的方法。但是,在 UI 工具包中使用此机制会产生性能问题,因为如果不立即计算某个值,则无法通知该值不再有效。这意味着,例如,对于 属性.

的每个单独更改都会重新计算布局

JavaFX 团队的目标显然是定义一种模式

  1. 符合标准的 JavaBean 模式,并且
  2. 支持的可观察属性,其中每次值更改时无需重新计算依赖值即可跟踪失效 ("lazily observable values")

因此 JavaFX 解决方案是创建支持 ChangeListeners 和 InvalidationListeners 的属性,前者在值更改时收到通知,后者在值不再有效时收到通知。这意味着,例如,布局机制可以跟踪它当前是否有效,而无需在它变得无效时强制重新计算。布局只会在实际屏幕脉冲时(即渲染场景时)重新计算,并且只有在它无效时才会重新计算。

(作为快速概念验证,请考虑以下内容:

DoubleProperty width = new SimpleDoubleProperty(3);
DoubleProperty height = new SimpleDoubleProperty(4);
ObservableDoubleValue area = Bindings.createDoubleBinding(() -> {
    double a = width.get() * height.get();
    System.out.println("Computed area: "+a);
    return a ;
}, width, height);
System.out.println("Area is "+area.getValue());
width.set(2);
height.set(3);
System.out.println("Area is "+area.getValue());

请注意,当 width 为 2 且 height 仍为 4 时,永远不会计算中间值。)

因此,JavaFX 中的值由这些支持失效侦听器和更改侦听器的可观察对象 Properties 表示,这意味着它们基本上是 "lazily observable"。通过 属性 访问器方法(在您的示例中为 amountProperty())公开 属性 本身足以支持此功能。

然而,从语义上讲,公开一个 DoubleProperty 意味着该 bean 具有 double 类型的值。为了保持与旧 JavaBean 约定的兼容性,这个 bean 应该通过公开相应的 getset 方法来宣传这一事实。因此,JavaFX 属性 模式需要 "property accessor" (amountProperty()) 以及标准 JavaBean 方法(getAmount()setAmount(...))。这意味着遵循 JavaFX 模式的 bean 可以在任何使用标准 JavaBean 模式的地方使用,例如 JPA.

请注意,为了使模式正常工作,amountProperty().get() == getAmount()amountProperty().set(x)setAmount(x) 具有相同的效果应该始终为真。这可以通过 getset 方法 final 来保证(即使 bean class 被子 classed),如您的示例所示。

如果您自己调用这些方法来检索或更改 属性 的值,调用哪个方法并不重要,因为它们保证具有相同的效果。由于 JavaFX 属性 模式是 JavaBean 模式的扩展,因此调用 getset 方法可能有轻微的偏好:在某种意义上访问值只需要 JavaBean功能,而不是完整的 JavaFX 属性 功能,因此仅依赖该功能可能具有一定的语义意义。然而,在实践中,使用哪种方式并没有什么区别。