Advantages of JavaFX builders

Very often one has to create a number of of similar objects. Using JavaFX builders for this task instead of constructors has several advantages as we will see in this article.

In short, builders…

  • are easier to read and understand
  • avoid some “copy & paste”-bugs
  • result in small, but simple code, if builders are reused

When using JavaFX, you typically have to create a number of similar objects with only few attributes different. For example your screen may contain buttons, which have the same size and style, but different locations, labels, and event handlers. Or you want to use similar transitions for some elements.

The traditional approach is to create all objects with constructors and configure them with setters. Listing 1 shows an example of three similar labels with the same font and color, but different locations and content.

final Text text1 = new Text(50, 50, "Hello World!");
text1.setFill(Color.WHITE);
text1.setFont(MY_DEFAULT_FONT);

final Text text2 = new Text(50, 100, "Goodbye World!");
text2.setFill(Color.WHITE);
text2.setFont(MY_DEFAULT_FONT);

final Text text3 = new Text(50, 150, "JavaFX is fun!");
text3.setFill(Color.WHITE);
text3.setFont(MY_DEFAULT_FONT);

 Listing 1: Creating similar objects with constructors

What an awful piece of code! We could put everything in a loop, which would make the code shorter, but definitely not simpler. Another option is to use builders straight-forward, one builder per created object. Listing 2 shows the code accomplishing the same task.

final Text text1 = TextBuilder.create()
    .text("Hello World!")
    .x(50).y(50)
    .fill(Color.WHITE)
    .font(MY_DEFAULT_FONT)
.build();

final Text text2 = TextBuilder.create()
    .text("Goodbye World!")
    .x(50).y(100)
    .fill(Color.WHITE)
    .font(MY_DEFAULT_FONT)
.build();

final Text text3 = TextBuilder.create()
    .text("JavaFX is fun!")
    .x(50).y(150)
    .fill(Color.WHITE)
    .font(MY_DEFAULT_FONT)
.build();

Listing 2: Creating similar objects with one builder per object

Obviously the code became longer, but in my opinion even this version is preferable for a number of reasons.

Builders are easier to read and understand

JavaFX Builders make it obvious which parameter sets which property. In the case of Text, we can guess, that probably the doubles set the location and the String sets the content. But often it is not that obvious. Take a look at this Rectangle creation for example:

final Rectangle rect = new Rectangle(100, 100, 50, 50);

Is (100, 100) the position or the size? Now compare that to the version using a builder. It is longer, but also a lot easier to understand:

final Rectangle rect = RectangleBuilder.create()
    .x(100).y(100)
    .width(50).height(50)
.build();

Builders avoid a number of possible “copy & paste”-bugs

Usually one creates code blocks like these in Listing 1 and 2 by typing the first part and using “copy & paste” for the rest. And almost always, when I do this, something goes wrong because I overlook a part that needs to be changed in the copied sections. 🙂 I guess, I am not the only one.

When you take a closer look at Listing 1 and 2, you will notice, that Listing 2 requires less changes in between the different code blocks. In Listing 1, the variable names text1, text2, and text3 are used several times, thus they also need to be changed several times. In Listing 2 the variable names are used only once.

Builders result in small, but still simple code, if reused

A not very well known and often overlooked feature of the JavaFX builders is, that they can be reused. Not only can they be reused to create similar objects, but also to create slightly different objects. Listing 3 shows how the three Text objects can be created with a reused builder.

final TextBuilder builder = TextBuilder.create()
    .x(50)
    .fill(Color.WHITE)
    .font(MY_DEFAULT_FONT);

final Text text1 = builder.text("Hello World!").y(50).build();
final Text text2 = builder.text("Goodbye World!").y(100).build();
final Text text3 = builder.text("JavaFX is fun!").y(150).build();

 Listing 3: Creating similar objects with a reused builder

Instead of calling the build() method immediately on the builder to get the created object, we store a reference to the builder and reuse it. The properties, which are common to all objects (x, fill, and font) have to be specified only once. Then we take the builder and set the properties, which are specific for a single object (content and y) and call build(). This will create an object with the properties as they are currently specified in the builder.

In my opinion, this is the best solution to create the three Text objects. It avoids code duplication; all common properties are only specified once. At the same time it is explicit, specifying exactly what is going on. And as a little bonus, “copy & paste”-bugs are almost completely avoided, because all properties in the copied sections have to be altered and are not as easily overlooked.

Conclusion

Next time you have to create a number of similar JavaFX objects, I encourage you to try the pattern above.

15 responses to “Advantages of JavaFX builders”

  1. tbee Avatar
    tbee

    The builders work great, but they do require a second set of code for each control. I know it is a “only needs to be done once”, but I’m wondering why they didn’t integrate it in the controls directly, using a specialized separate setter. Like:

    Text text1 = new Text()
    .text(“Hello World!”)
    .x(50).y(50)
    .fill(Color.WHITE)
    .font(MY_DEFAULT_FONT);

  2. Anatoliy Avatar
    Anatoliy

    Simple and cool post! Tnx!

  3. Pedro Duque Vieira Avatar

    Yes, builders are indeed a nice addition.

    I miss binding support for builders, though.
    Without it one can only use builders sparingly.. It would be nice to be able to pass in propertys using builders.

    Cheers

    1. Mike Avatar

      @Pedro Duque Vieira:
      I totally agree. Support for bindings in builders is missing. There is a feature request for this in JIRA.

  4. bilaalsoidik Avatar

    @tbee says “why they didn’t integrate it in the controls directly” because the builder pattern specifies how to use it as is implemented in JavaFX 2.x . Some thing else ,think about those methods, don’t forget that every method that will be use to create control, like in your example, must return the object itself; So that many methods will be included in the object that will be difficult for user to recognize the methods that must be used to build and those who must be used to set attributes.

  5. […] Speaking of the builder classes shipped with JavaFX, Michael Heinrichs, a member of the JavaFX team, has put up a post about the advantages of the JavaFX builder APIs. […]

  6. Hans-Henry S Avatar
    Hans-Henry S

    This is very useful in practice.
    I have created a library, comparable to ScalaFx, which I call EasyFX, in which the same is achieved through the following statements:

    def textTmp (n:wText) { // “text-template”
    n.x = 500
    n.fill = BLACK
    n.font = MY_DEFAULT_FONT
    }
    val text1 = new wText (“Hello World!” ) { textTmp(this); y = 50; >>}
    val text2 = new wText (“Goodbye World!” ) { textTmp(this); y = 100; >>}
    val text3 = new wText (“JavaFX is fun!” ) { textTmp(this); y = 150; >>}

    HHS

  7. Hans-Henry S Avatar
    Hans-Henry S

    Forgot to mention:
    Binding is offered in “Visage-style”, like

    n.x <– anXposWhichMightChange
    n.fill <– aColorWhichMightChange

    HHS

  8. Peter Avatar

    Hi, Michael.
    I have unrelated question. And I desperately need JavaFX professional to help me. Imagine text(or any other) control, that you go over the text and mark some parts of the text regions with mouse and then tell(programmatically) “I assign yellow background to that specific text, I also assign some metadata for that text region”, what javafx component is most close to that function? If not javafx, what applet/swing component is close? Thanks ! Peter.

  9. Mike Avatar

    Hi Peter,

    that is an interesting question. I am not aware of any component that provides such functionality out-of-the-box. I can see this as a useful component for a number of applications, would be nice to add it to the runtime.

    I am not an expert for the UI components and especially I am not aware of all the third party development of new controls, that is going on. The best place to ask such question is the Oracle Forum. There is a section for JavaFX 2.0. A lot of JavaFX team members and other community members read it regularly. I am sure you will get a better answer there. Here is the link: https://forums.oracle.com/forums/forum.jspa?forumID=1385

    Hope that helps,
    Michael

  10. Abraham Avatar
    Abraham

    Hi Michael,

    Thanks for the post. I can clearly see the benefits of using builders and we have been using them in some areas in our code. Your post made me realize that reusing builders can be really powerful. Our application has a number of TableViews and each view has a number of columns. The builders are a perfect fit for the scenario where you want to create a number of columns that have many properties in common. You can use a TableColumnBuilder to create partial specification for the column and then stamp out the columns by setting the unique properties for each column and build() them (Similar to your text1, text2, text3 example above). The only problem is builders are not immutable. Every time you set a property on the builder it affects all future build events. In you example above, if you only want text2 to be green it would be nice if you were able to call it as follows:

    final Text text1 = builder.text(“Hello World!”).y(50).build();
    final Text text2 = builder.text(“Goodbye World!”).y(100).fill(Color.GREEN).build();
    final Text text3 = builder.text(“JavaFX is fun!”).y(150).build();

    But this results in both text2 and text3 turning green.

    I think making builders immutable will significantly improve the ability to reuse them. Consider the following example:

    TableColumnBuilder standardColumnBuilder = TableColumnBuilder.create()
    .prefWidth(50.0)
    .sortable(false)
    .editable(false);
    TableColumnBuilder narrowColumnBuilder = standardColumnBuilder
    .prefWidth(40.0)
    .resizable(false);
    TableColumnBuilder narrowColumnBuilder = narrowColumnBuilder
    .prefWidth(80.0);

    If builders were immutable I would now have three templates that I could reuse to build all the table columns but because they are not immutable I now have a ‘standardColumnBuilder’ that is not resizable and has a width of 80.

    Cheers,
    Ab

    1. Mike Avatar

      That is a wonderful idea! I tripped over this issue a couple of times already. You have to set the fill-color back for text3 in the example. And suddenly the order in which you create text1, text2, and text3 becomes important. Or you have to set the fill-color for all three Textnodes, just because you want to change one of them… I wish we had this idea when we designed builders. 🙂

  11. Charles Kingsbury Avatar
    Charles Kingsbury

    I am frying to use the Polygon builder to generate regular polygons. When I use the Polygon builder on a simple polygon it does not display.

    What do I need to do to display a golygon generated with the polygon builder? I will look at arc builder that would be better for regular polygons if thy will close. I wii play with some other builders/

    1. Mike Avatar

      Hi Charles,

      using a builder does not change the functionality of the generated object itself. It has the same result as if you would call the constructor and setters of the polygon. The issue must be somewhere else. Can you post some code? Without knowing the code, it is hard to guess what the problem may be.

  12. […] Java applications more intuitive. As part of this, mouse event handling in JavaFX and the common JavaFX idiom of using builders are both demonstrated. A practical use of this application is to quickly and easily determine the […]