What the model-view-controller pattern is
What other variants of the model-view-controller pattern are, such as the model-view-presenter pattern
How to develop a JavaFX application using the model-view-presenter pattern
What Is the Model-View-Controller Pattern?
Domain code that deals with domain-specific data and business rules
Presentation code that deals with manipulating user interface widgets
It is often required that the same data in a specific domain be presented in different forms. For example, you may have a web interface using HTML and a desktop interface using JavaFX to present the same data. For easy maintenance of the application code, it is often necessary to divide the application into two logical modules where one module contains presentation code and another domain code (domain-specific business logic and data). The division is made in such a way that the presentation module can see the domain module, but not vice versa. This type of division supports multiple presentations with the same domain code.
In MVC, the model consists of the domain objects that model the real-world problems. The view and controller consist of the presentation objects that deal with the presentation such as input, output, and user interactions with GUI elements. The controller accepts the inputs from the users and decides what to do with it. That is, the user interacts with the controller directly. The view displays the output on the screen. Each view is associated with a unique controller and vice versa. Each widget on the screen is a view, which has a corresponding controller. Therefore, there are typically multiple view-controller pairs in a GUI screen. The model is not aware of any specific views and controllers. However, views and controllers are model specific. The controller commands the model to modify its state. The views and model always stay in sync. The model notifies views about changes in its state, so views can display the updated data. The model-to-view interaction is facilitated through an observer pattern. Keep in mind that the model is fully unaware of any specific views. The model provides a way for views to subscribe to its state change notifications. Any interested views subscribe to the model to receive state change notifications. The model notifies all views that had subscribed whenever a model’s state changes.
What has been described so far about the MVC pattern is the original concept of MVC that was used in developing user interfaces in the Smalltalk-80 language that was created in 1980. There have been many variants of Smalltalk. The concept in MVC that the presentation and domain logic should be separated in a GUI application still holds true. However, in MVC, dividing the responsibilities between three components had issues. Which component, for example, will have the logic to update the attributes of the view, such as changing the view color or disabling it, that depend on the state of the model? Views can have their own states. A list that displays a list of items has the index of the currently selected item. The selected index is the state of the view, not the model. A model may be associated with several views at one time, and it is not the responsibility of the model to store the state of all views.
In MVC, each widget on the screen is a view, and it has its own unique controller. In MVP, the view is composed of several widgets. The view intercepts the inputs from the user and hands over the control to the presenter. Note that the view does not react to the user inputs. It only intercepts them. The view is also responsible for displaying the data from the model.
The presenter is notified by the view about the user inputs. It determines how to react to the user’s input. The presenter is responsible for the presentation logic, manipulating the view, and issuing commands to the model. Once the presenter modifies the model, the view is updated using the observer pattern, as was done in MVC.
The model is responsible for storing domain-specific data and logic. Like MVC, it is independent of any views and presenters. The presenter commands the model to change, and the view updates itself when it receives state-changed notifications from the model.
The concept of MVC that the presentation logic should be separated from the domain logic has been around for over 30 years, and it is going to stay in one form or another. All variants of MVC have been attempting to achieve the same function of what the classic MVC did, though in different ways. The variants vary from the classic MVC in the responsibilities of their components. When someone talks about MVC in a GUI application design, make sure you understand which variant of MVC is used and which components perform which tasks.
A Model-View-Presenter Example
This section presents a detailed example that uses the MVP pattern.
The Requirements
Person ID field: An autogenerated unique noneditable field
First name field: An editable text field
Last name field: An editable text field
Birth date: An editable text field
Age category: An autocomputed noneditable field based on the birth date
Save button: A button to save the data
Close button: A button to close the window
The first and last names must be at least one character long.
If a birth date is entered, it must not be a future date.
The Design
Person class
PersonView and PersonPresenter classes
The Person class represents the model, the PersonView class the view, and the PersonPresenter class the presenter. As required by the MVP pattern, the Person class will be agnostic about the PersonView and the PersonPresenter classes. The PersonView and the PersonPresenter classes will interact with each other, and they will use the Person class directly.
The Implementation
The following paragraph describes the implementation of the three layers of the MVP example application.
The Model
The Person Class Used As the Model
The person ID, first name, last name, and birth date are represented by JavaFX properties. The personId property is declared read-only, and it is autogenerated. Relevant setter and getter methods are provided for these properties.
The isValidBirthDate() and isValidPerson() methods are included to perform domain-specific validations. The getAgeCategory() method belongs to the Person class as it computes the age category of a person based on their birth date. I have made up some date ranges to divide the age of a person into different categories. You may be tempted to add this method to the view. However, you would then need to duplicate the logic inside this method for each view. The method uses the model data and computes a value. It knows nothing about views, so it belongs to the model, not to the view.
The save() method saves the personal data. The save method is trivial; it simply displays a message on the standard output if the personal data are valid. In a real-world application, it would save the data to a database or a file.
The View
The PersonView Class Used As the View
The PersonView class inherits from the GridPane class. It contains an instance variable for each UI component. Its constructor takes the model (an instance of the Person class) and a date format as arguments. The date format is the format used to display the birth date. Note that the format for the birth date is view specific, and it should be part of the view as such. The model knows nothing about the format in which the birth date is displayed by views.
The initFieldData() method initializes the view with the data. I used JavaFX bindings to bind the data in UI nodes to the model data except for the birth date and age category fields. This method synchronizes the birth date and the age category fields with the model. The layoutForm() method lays out the UI nodes in the grid pane. The bindFieldsToModel() method binds the person ID, first name, and last name TextFields to the corresponding data fields in the model, so they stay in sync. The syncBirthDate() method reads the birth date from the model, formats it, and displays it in the view. The syncAgeCategory() method synchronizes the age category field, which is computed by the model based on the birth date.
Notice that the view, the PersonView class, does not know about the presenter, the PersonPresenter class. So how will the view and the presenter communicate? The role of a presenter is mainly to get the user’s inputs from the view and act upon them. The presenter will have a reference to the view. It will add event listeners to the view, so it is notified when the data in the view change. In the event handlers, the presenter takes control and processes the inputs. If the application requires a reference to the presenter in the view, you can have that as an argument to the constructor of the view class. Alternatively, you can provide a setter method in the view class to set the presenter.
The Presenter
The PersonPresenter Class Used As the Presenter
You attach a focus listener to the scene and detect if the birth date has lost the focus.
You attach an action listener to the birth date field, so you intercept the Enter key press while the field has focus.
This validates and refreshes the birth date and age category whenever the birth date field loses focus or the Enter key is pressed while focus is still in the field.
The handleBirthDateChange() method handles a change in the birth date field. It validates the birth date format before updating the model. It displays an error message to the user if the birth date is not valid. Finally, it tells the view to update the birth date and age category.
The saveData() method is called when the user clicks the Save button, and it commands the model to save the data. The showError() method does not belong to the presenter. Here, you added it instead of creating a new view class. It is used to display an error message.
Putting Them Together
The PersonApp Class Uses the Model, View, and Presenter to Create a GUI Application
Summary
It is often required that the same domain data be presented in different forms. For example, you may have a web interface using HTML and a desktop interface using JavaFX to present the same data. For easy maintenance of the application code, it is often necessary to divide the application into two logical modules where one module contains presentation code and another domain code (domain-specific business logic and data). The division is made in such a way that the presentation module can see the domain module, but not vice versa. This type of division supports multiple presentations with the same domain code. The MVC pattern is the oldest and the most popular pattern to model GUI applications to facilitate such a division. The MVC pattern consists of three components: model, view, and controller.
In MVC, the model consists of the domain objects that model the real-world problems. The view and controller consist of the presentation objects that deal with the presentation such as input, output, and user interactions with GUI elements. The controller accepts the inputs from the users and decides what to do with them. That is, the user interacts with the controller directly. The view displays the output on the screen. Each view is associated with a unique controller and vice versa. Each widget on the screen is a view, which has a corresponding controller. In MVC, dividing the responsibilities between three components created issues. Which component, for example, would have the logic to update the attributes of the view, such as changing the view color or disabling it, that depend on the state of the model?
The issues of which component in MVC has the responsibility of storing the view logic and the state led to another variant of MVC called the Application Model MVC. In AM-MVC, a new component, called the Application Model, was introduced between the model and the view/controller. Its purpose is to contain the presentation logic and the state, thus solving the issue of which component keeps the presentation logic and state in the original MVC.
Later, modern graphical operating systems like Microsoft Windows and Mac OS offered native widgets, which users can interact with directly. These widgets combined the functions of the view and controller into one. This led to another variant of MVC, called the model-view-presenter pattern.
In MVC, each widget on the screen is a view, and it has its unique controller. In MVP, the view is composed of several widgets. The view intercepts the inputs from the user and hands over the control to the presenter. Note that the view does not react to the user’s inputs; it only intercepts them. The presenter is notified by the view about the user’s inputs and determines how to react to them. The presenter is responsible for the presentation logic, manipulating the view, and issuing commands to the model. Once the presenter modifies the model, the view is updated using the observer pattern, as was done in MVC.
There are some variants of MVP as well. They vary in the responsibility of the view and the presenter. In one variant, the view is responsible for all view-related logic without the help of the presenter. In another variant, the view is responsible for all the simple logic that can be handled declaratively, except when the logic is complex, which is handled by the presenter. In another variant, the presenter handles all view-related logic and manipulates the view. This variant is called passive view MVP, in which the view is unaware of the model.
The next chapter will introduce you to controls that are used to build the view in JavaFX applications.