This decoupling allows independent and segregated module development, runtime fault tolerance through isolating modules, easier testing of standalone modules, and a logical separation of dependencies.
This screenshot shows a multi-Stage Java FX Application. A primary Stage is created from a JavaFX Application subclass. This is the Core screen with buttons Show A - Show D along its left side. Buttons Show A - Show D will display other Stages. For example, pressing Show A displays Screen A, running in a new Stage.
|Buttons on a Primary Stage Launch Other Stages|
|FXML Files Paired with Controller Classes|
|IntelliJ Project Structure Showing Grouping of FXML and Controller Classes|
At this point, I have FXML and Controller classes grouped in packages. All of this can be pulled together in a static fashion (no dynamic loading). I could make HomeScreenController aware of the contents of the subapp_* packages' FXML and Controller, creating buttons for each subapp_* package. I would then provide a handler for each button that would create the objects in a subapp_* package. My terminology and package design aside, you've done something similar if you've coded an FX app.
By breaking the project up into packages, I've shown a good logical design. This helps keep code focused for developers browsing the codebase. Also, packages help to decrease coupling and increase information hiding, particularly where package-level access is used.
The logical structure is shown in the following package diagram. A toplevel Main class initializes app_core, starting with HomeScreenController. app_core contains a discovery mechanism, but does not explicitly refer to any of the other modules. The inverse relationship is different, the other modules do know of app_core which provides shared services. There is a framework package that is off to the side, this is a common library known to all classes.
|SubApps Know About Core, but Core Doesn't Know About SubApps|
|SubApp D is Completely Separate from the Rest of the Project|
Being able to segregate components and development out in this way is helpful on a number of fronts:
- Fault Tolerance,
- Intellectual Property, and
- Platform Stability.
Secondly, for a team, the business might not want every developer having access to a full set of source code. In fact, an independent team may want to develop a module outside of a binding legal agreement. If a team can install a single JAR and see its functionality realized, drawing off of common system services, the overall app may become more useful.
Finally, SubApps give developers rules for engagement in working with common services and initialization. That is, a new feature doesn't require a developer to dive into a mission critical initialization code block to add their new feature.
To build the app in Figure "Buttons on a Primary Stage Launch Other Stages" takes about 20 minutes in Scene Builder and if you're working solo, that may all you need to do. But if you're confronted with a larger project -- say a porting project with 7 developers, 3k legacy files, etc -- you don't want the design to hit a wall by compiling everything together and pushing out single JAR. Look for the next part of the series that will introduce the role of dependency injection in the Dynamic SubApps.
Click Dynamic FX Application Modules - Part 2 - Foundation - Google Guice for the next part of the series.