This is just auxiliary comment on some different, but related (and sometimes advanced) topics, and is not a direct answer to the question (which is already well answered in other answers). Perhaps the info here is not relevant for here or your question, if so, just ignore it :-)
On Immutability, i.e., Just Not Adding Setters
Getters are usually fine as the caller can't change the object, but unnecessary setters can make it more difficult to reason about an object, especially when writing concurrent code.
When you have setters, the source of the object's change can come from a wider area, another class and even another thread.
See Immutable Objects in the Java tutorials and a synchronized sample with setters which is just plain more complicated and potentially error prone vs an immutable version without setters.
The JavaFX Color class is an example of an immutable class in the JDK.
Generally, when I make a class, I usually try to put all of the inputs into constructor parameters, make the class final, not add setters and make all the members of the class final. You can't always do that, but when you can it seems to make programming easier to me.
Note, setters are often useful and necessary, so don't worry about adding them in if you need them, immutability is just a sometimes desirable attribute and not a rule.
On bridging the data model and the display
If you are really interested in different patterns and conventions of getting data from the object to display, then read Martin Fowler's GUI Architectures as it gives a very good overview of this.
Usually, you want a separation of concerns from the data and domain objects and the UI. For small apps, you don't need that separation and it is just more overhead. But, as soon as you start developing larger apps, it usually becomes a lot better organized if you separate the UI from the domain model completely. Usually, observables help to do this, often coupled with a design pattern like MVC, MVP or MVVM.
On JavaFX Properties and Binding to the Display
If using JavaFX, as you mention in your question, properties and binding provide an observable interface so a change in your domain object can be reflected automatically in your UI. You can define the properties directly in your data and domain classes. You can define your UI using something like FXML and an FXML Controller. In the controller you can bind properties of the UI (e.g. the text string of a Label) to properties in your data and domain objects. That way, if you internally change the value of a property in your domain, e.g. the number of books in the library, you can expose that number as a property which is automatically updated in the UI whenever a new book is added (without you having to explicitly tell the UI to update the label when the book is added).
For example in your LibraryController, you might have:
@FXML
Label numberOfBooksInLibraryLabel;
Library library = new Library();
...
numberOfBooksInLibraryLabel.textProperty().bind(
library.books().sizeProperty().asString()
);
On JavaFX Properties and Encapsulation
JavaFX has some conventions around JavaFX properties which are a bit more complex and subtle than plain Java without JavaFX. To help with encapsulation and JavaFX properties, consider using FXCollections.unmodifiableObservableList()
and read only properties.
private final ReadOnlyDoubleWrapper size = new ReadOnlyDoubleWrapper();
public final double getSize() {
return size.get();
}
public final ReadOnlyDoubleProperty sizeProperty() {
return size.getReadOnlyProperty();
}