Mastodon

JavaFX Series - Separation & Life Cycle

With the last post of this series, I started experimenting with JavaFX. Since then, I figured out how to separate the user interface (UI) framework from the business logic and how the life cycle of the objects should be like.

First impressions

As I explained before, I want to write a small simulation in which some civilization uses growing resources to expand. The whole idea is pretty scetchy right now, but there should be a bord on which the whole simulation takes place and the mentioned resources. Because resources don’t grow on their own, there are resource spawners that can be set programmatically and appear on the UI. These things spawn new resources every time the user clicks on them. The new resources (yellow thingies) are spread in a random fashion around the spawners (grey buttons):

SimFX First Impressions

Package Hierarchy & Life Cycle

My refined package hierarchy looks as follows. The numbers in the diagram show in which order the packages are accessed.

JavaFX Series Package Hierarchy

  1. General application setup. Currently there is just one class that decides what UI is used.Every setup for other UI frameworks has to go here. 1.UI-specific classes. The class JavaFXApplication in the package ui.javaFX is a subclass of javafx.application.Application and thus starts the FX frontend.
  2. After starting the frontend, the business logic in form of the class World is instantiated. Every business decision, such as creating the world with two resource spawners, is made in the business package. That way, the business logic is isolated from the UI. To get notified of changes in the business layer (for example new grown resources from the spawners), the JavaFXApplication offers the method notifyCreation(WorldObject newWorldObject). The class ResourceSpawner in the business package creates the new resource and cares about everthing business-specific. After that, it notifies the UI that it can display the new object. How a business object can be displayed in a UI is described in the next section.

Business Objects and Graphical Representations

Because my business layer has to be independent from the UI layer, business objects that are visible to the user must not hold any specifics of their appearance. The business class Resource for example only knows where it is positioned in the world, but not how it will look like. That is the responsability of the UI:

public class Resource implements WorldObject {

        // (only holds x and y coordinates)
	private CartesianCoordinate position;

	public Resource(CartesianCoordinate position) {
		super();
		this.position = position;
	}

	public CartesianCoordinate getPosition() {
		return position;
	}
}

As you can see above in the class diagram, there is a package worldObjects in the business- and in the ui-package. For every business class that is visible on the UI (namely worldObjects), there is a graphical representation class. This class encapsulates the represented business class and cares about the graphical representation. Hence, these classes are UI framework specific. That is the reason why ResourceFX, the graphical representation of the business class Resource for the framework JavaFX, is a subclass of Polygon which is a JavaFX class:

public class ResourceFX extends Polygon {

	private Resource representedResource;

	public ResourceFX(final Resource representedResource) {
		super(new double[] { 0, 0, 10, 10, 20, 0, 20, 10, 30, 20, 20, 20, 20,
				30, 10, 30, 0, 20, 10, 20 });
		this.setFill(Color.CORAL);
		this.representedResource = representedResource;
		setLayoutX(representedResource.getPosition().getX());
		setLayoutY(representedResource.getPosition().getY());
	}
}

As I described, the business logic is started after the UI has been initialized. At first, I tried to implement it the other way around. First the World-class which holds all other business classes was instantiated, then the two resource spawners where added. Only after that the JavaFX UI was started. That worked fine for this static setup. But because a JavaFX application never leaves the launch() method except when being closed, there was no way to add more world objects after starting the UI. This lead to the new hierarchy as described above.

Get the Code

I pushed the code in my repository on github. The codebase for this article is tagged as Codebase_SeparationAndLifeCycle.

Next Steps

The next step will be to add some more logic, maybe visually growing resources that disappear after a while. Maybe I will jump ahead and style the growing resources with the powers of CSS.

What do you think - will my concept of separating the business layer from the UI hold? What should I implement next?