11

I am familiar with Java, but just starting to learn JavaFX, and specifically learn about JavaFX properties. I understand the basic design pattern as shown in the following example from 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;}

}

What I don't understand is when/why I would use the getter and setter methods, instead of using the Property directly?

What I was thinking is that you may want some custom code in the getter and/or setter that may do some pre or post manipulation/validation of the data, but if you create a custom getter and/or setter, you would get different results then, depending on whether you use the getter/setter or property directly, which to me, seems dangerous.

If the getter/setter simply call the Property's get and set methods, then why even have them?

Any insights into this would be appreciated.

vewert
  • 113
  • 2
  • 7
  • from [learn javafx ebook](http://www.apress.com/9781484211434) . `Additional getters and setters, using JavaBeans naming convention, are added to make the class interoperable with the older tools and frameworks that use the old JavaBeans naming conventions to identify the properties of a class. ` – Kachna Nov 20 '15 at 20:02
  • In my opinion, Additional getters and setters are not required. – Kachna Nov 20 '15 at 20:08
  • @Kachna Surely that depends on your use case. Eg if you want to use JavaFX properties in a JPA entity, you would need the get and set methods. Similarly if you are using JSON or XML marshalling, etc. – James_D Nov 20 '15 at 20:17

1 Answers1

18

The JavaFX property pattern is designed to extend the old, standard JavaBean pattern. So in your example, according to the JavaBean convention, you have a (read-write) property of type double called amount. This is determined by the two methods

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

The JavaBean pattern allows some limited "observability" via "bound properties", in which beans support registering a PropertyChangeListener. A UI toolkit often has need to observe properties and respond to changes. For example, it makes sense for a Label to have a text property. If the text property changes, the Label needs to be notified, so that it knows to repaint itself. At first glance, using JavaBeans with bound properties would be a way to do this. However, using this mechanism in a UI toolkit produces performance issues, because there is no way to have notifications that a value is no longer valid without computing it immediately. This means, for example, that layout would be recomputed on every individual change to a property.

What the JavaFX team apparently were aiming to do was define a pattern that

  1. conformed to the standard JavaBean pattern, and
  2. supported observable properties where invalidation could be tracked without recomputing dependent values every time the value changed ("lazily observable values")

So the JavaFX solution is to create properties which support both ChangeListeners, which are notified when a value changes, and InvalidationListeners, which are notified when a value is no longer valid. This means that, for example, a layout mechanism can track whether or not it is currently valid without forcing a recomputation when it becomes invalid. The layout will only recompute on an actual screen pulse (i.e. when the scene is rendered), and only if it is invalid.

(As a quick proof-of-concept, consider the following:

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());

Note here that the intermediate value, when width is 2 and height is still 4, is never computed.)

So values in JavaFX are represented by these observable Properties which support both invalidation listeners and change listeners, meaning they are basically "lazily observable". Exposing the property itself via a property accessor method (amountProperty() in your example) is enough to support this functionality.

Semantically, however, exposing a DoubleProperty means the bean has a value of type double. In order to maintain compatibility with the old JavaBean convention, this bean should advertise this fact by exposing the corresponding get and set methods. Consequently, the JavaFX Property pattern requires both a "property accessor" (amountProperty()) as well as the standard JavaBean methods (getAmount() and setAmount(...)). This means that beans following the JavaFX pattern can be used anywhere the standard JavaBean pattern is used, for example in JPA.

Note that for the pattern to work correctly, it should always be true that amountProperty().get() == getAmount() and that amountProperty().set(x) has the same effect as setAmount(x). This is guaranteed (even if the bean class is subclassed) by making the get and set methods final, as in your example.

If you are invoking the methods yourself to retrieve or change the value of the property, it doesn't matter which you call, since they are guaranteed to have the same effect. Since the JavaFX Property pattern is an extension of the JavaBean pattern, there may be a very slight preference to call the get and set methods: in a sense accessing the value only needs the JavaBean functionality, not the full JavaFX property functionality, so it might make some semantic sense to only rely on that functionality. In practice, however, it makes no difference which you use.

James_D
  • 201,275
  • 16
  • 291
  • 322
  • 1
    Thank you for your detailed explanation. What about the case where the setter actually manipulates the data, for example if you have a StringProperty firstName: `firstName.set(name.trim())` In this case calling the setter method is different than calling `set()` on the property, or is this a no-no with JavaFX Properties. – vewert Nov 24 '15 at 23:57
  • Sorry, I wanted to add a more detailed example, but it seems you can't add code blocks to comments. – vewert Nov 24 '15 at 23:59
  • 1
    You would be breaking multiple conventions by that example. As mentioned, in the JavaFX property pattern you should guarantee that `setFirstName(x)` is equivalent to `firstNameProperty().set(x)`. But in the regular Java Bean pattern, you should really guarantee that `setFirstName(x); getFirstName()` evaluates to `x`, assuming no other operations occur on the object between the two method calls. If you really wanted to do something like that, subclass `StringPropertyBase` and override `setString(...)` and `setValue(String)`. – James_D Nov 25 '15 at 02:39
  • @James_D, did you mean override set(String) and String get()? In particular, StringPropertyBase does not seem to have a setString method. – user118967 Feb 26 '18 at 00:17