ReadOnlyIntegerProperty

JavaFX 8 只读属性(ReadOnly Properties)

将内部可修改属性设置为对外部只读

假如你使用JavaFX开发一个系统,其中有些属性对用户操作是只读的,而在应用内部又要求这些属性是可以更新的。怎样实现这样两面性需求呢?本文介绍JavaFX 8采取的解决方案。

只读属性的使用场景

下面的代码是如何创建对外部用户是只读的属性,先回顾如何定义一个简单的属性。代码段 1 是实现 age 属性的类

代码段 1

Age 类,包含了javafx.beans.property.IntegerProperty用于定义封装了32位整型数值的 age. 由于IntegerProperty是抽象的,所以需要使用一个具体的类将其实例化,这里使用的是javafx.beans.property.SimpleIntegerProperty, 这个类的无参数构造器将age属性的值初始化为0

ageProperty() 方法返回一个JavaFX属性,可以添加change listener和绑定之类的。getAge()方法返回属性的当前值。上面没有对应的setAge()方法,因为age不可被设置为任意整数值。

更改这个属性的值的任务交给了increment()方法。

代码段 2 是使用Age类的例子。

代码段2

UseAgemain()方法首先实例化Age,然后添加一个change listener到这个属性。 每当age的值发生变化,就会调用listener并打印输出,旧的值和新的值。 main()方法通过调用Age类的increment() 方法10次,对age的属性值进行10次修改。 编译运行输出结果如下:

但是age属性的实现存在问题,尽管没有setAge()方法,外部代码很容易绕过increment()方法,给age赋任意整数值。你可以在Age = new Counter(); 之后插入这语句:a.ageProperty().set(-10);重新编译运行代码,输出如下:

上文说到age不可被设置为任意整数值,然而上面的输出说明Age的属性值仍然可以被修改,这不满足只读属性的要求。下面介绍如何解决这问题。

使用只读属性

代码段 1里面的ageProperty() 方法是很有问题的,因为它破坏了Age的封装性,向外暴露了age属性。你可以去掉这个方法,这样问题就解决了,不过外部代码就无法绑定,或添加listner到age属性了。还好,JavaFX的设计者预先考虑到这种情形,并提供了一个比较优雅的解决方案。

java.beans.property包里面有很多带有ReadOnly前缀的类。紧接前缀是类型名,例如BooleanIntegerListMap。而后缀是PropertyPropertyBase,或者是Wrapper。 例如,这包里会有ReadOnlyIntegerProperty, ReadOnlyIntegerPropertyBase, 和 ReadOnlyIntegerWrapper 这些类在里面。

ReadOnlyIntegerProperty 等具体类定义了相应类型的只读属性值(如32位宽整型数值)。ReadOnlyIntegerWrapper等具体类定义了两种同步的属性,其中一种是外部可访问的只读属性,而另外一种属性是内部可更新但不对外暴露。代码段 3 是使用ReadOnlyIntegerPropertyReadOnlyIntegerWrapper实现可更改对外为只读的age属性。

代码段 3

 

 

 

 

发表评论