JavaFX Tip 3: Use Callback Interface
As a UI framework developer it is part of my job to provide ways to customize the appearance and behavior of my controls. In many cases this is done by allowing the framework user to register a factory on a control. In the past I would have created a factory interface for this and provided one or more default implementations within the framework.
These things are done differently in JavaFX and I have started to embrace it for my own work. JavaFX uses a generic interface called javafx.util.Callback wherever a piece of code is needed that produces a result (R) for a given parameter (P).
The interface looks like this:
public interface Callback<P,R> { public R call(P param); }
Advantages
At first I didn’t like using this interface because my code was loosing verbosity: I no longer had self-explaining interface names. But in the end I realized that the advantages overweight the lack of verbosity. The advantages being:
- We end up writing less code. No specialized interface, no default implementations.
- The developer using the API does not have to remember different factories, instead he can focus on the object that he wants to create and the parameters that are available to him.
- The Callback interface is a functional interface. We can use Lambda expressions, which makes the code more elegant and we once again have to write less code.
Case Study
The FlexGanttFX framework contains a control called Dateline for displaying (surprise) dates. Each date is shown in its own cell. The dateline can display different temporal units (ChronoUnit from java.time, and SimpleUnit from FlexGanttFX). A factory approach is used to build the cells based on the temporal unit shown.
Before I was using the callback approach I had the following situation: an interface called DatelineCellFactory with exactly one method createDatelineCell(). I was providing two default implementations called ChronoUnitDatelineCellFactory and SimpleUnitDatelineCellFactory. By using Callback I was able to delete all three interfaces / classes and in the skin of the dateline I find the following two lines instead:
dateline.setCellFactory(<span class="skimlinks-unlinked">SimpleUnit.class</span>, unit -> new SimpleUnitDatelineCell()); dateline.setCellFactory(<span class="skimlinks-unlinked">ChronoUnit.class</span>, unit -> new ChronoUnitDatelineCell());
Two lines of code instead of three files! I think this example speaks for itself.
Reference: | JavaFX Tip 3: Use Callback Interface from our JCG partner Dirk Lemmermann at the Pixel Perfect blog. |