JavaFX属性模式旨在扩展旧的标准JavaBean模式。因此,在您的示例中,根据JavaBean约定,您有一个名为
amount
的
double
类型的(可读写)属性。这是由两个方法确定的。
public double getAmount() ;
public void setAmount(double amount);
JavaBean模式允许通过"绑定属性"进行一些有限的"可观察性",其中bean支持注册
PropertyChangeListener
。UI工具包通常需要观察属性并响应更改。例如,一个
Label
具有
text
属性是有意义的。如果
text
属性更改,
Label
需要被通知,以便它知道重新绘制自己。乍一看,使用具有绑定属性的JavaBeans可能是实现这一点的一种方法。但是,在UI工具包中使用此机制会产生性能问题,因为没有办法在不立即计算它的情况下通知值不再有效。这意味着,例如,布局将在每个单独的属性更改时重新计算。
JavaFX团队显然的目标是定义一种模式,该模式符合标准的JavaBean模式,并支持可观察属性,其中可以跟踪无效状态而无需每次更改值时重新计算依赖值("惰性可观察值")。
因此,JavaFX的解决方案是创建支持
ChangeListener
和
InvalidationListener
的属性。当值发生变化时,
ChangeListener
会被通知,当值不再有效时,
InvalidationListener
会被通知。这意味着,例如,布局机制可以跟踪它当前是否有效,而不会在其无效时强制重新计算。布局仅会在实际屏幕脉冲(即场景渲染时)上重新计算,并且仅在其无效时才会重新计算。(作为一个快速概念验证,请考虑以下内容:)
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中,值由这些可观察的属性
表示,它们支持无效化监听器和更改监听器,这意味着它们基本上是“懒观察”的。通过属性访问器方法(例如您的示例中的amountProperty()
)公开属性本身就足以支持此功能。
从语义上讲,暴露一个
DoubleProperty
意味着 bean 具有
double
类型的值。为了与旧的 JavaBean 约定保持兼容性,该 bean 应通过公开相应的
get
和
set
方法来广告这一事实。因此,JavaFX 属性模式需要 "属性访问器"(
amountProperty()
)以及标准的 JavaBean 方法(
getAmount()
和
setAmount(...)
)。这意味着遵循 JavaFX 模式的 beans 可以在任何使用标准 JavaBean 模式的地方使用,例如在
JPA 中。
请注意,为了使模式正常工作,应始终满足
amountProperty().get() == getAmount()
和
amountProperty().set(x)
具有与
setAmount(x)
相同的效果。通过将
get
和
set
方法设为
final
(就像您的示例中一样),可以保证这一点,即使 bean 类被子类化也是如此。
如果您自己调用方法来检索或更改属性的值,则无论您调用哪个方法,它们都保证具有相同的效果。由于JavaFX Property模式是JavaBean模式的扩展,因此可能稍微倾向于调用
get
和
set
方法:从某种意义上说,访问值只需要JavaBean功能,而不是完整的JavaFX属性功能,因此仅依赖该功能可能在语义上有些合理。但实际上,您使用哪个方法并没有任何区别。