When writing GUI programs, it is common practice to separate the "backend" data and data operations from the "frontend" GUI the user interacts with. Model-View-Controller (MVC) is a common design pattern used to separate frontend from backend.
The Model in a program stores the underlying data and handles operations on the data that is independent of the GUI. For example, if you were writing a Chess game, you could have a 2D array of Piece objects that represents the internal board. This 2D array would be stored in its own class along with methods to perform operations on the data. Here are some methods you might have in your model class:
public boolean isValidMove(Piece p, Location dest)
public void moveTo(Piece p, Location dest)
public List<Location> getValidMoves(Piece p)
public Piece getPieceAt(int row, int col)
Separating the Model from the GUI makes the Model reusable in other programs along with being easier to maintain and debug since it does not have anything to do with the GUI.
The View in a program is how the underlying model is presented to the user. The View is responsible for translating the model data into a form visible to the user. For example, the View for a chess game could contain a GridPane of ImageViews where each ImageView represents a chess piece image in the GUI. It wouldn't matter if the chess pieces were stored in the Model as integers, Strings, or something else. The View would translate the model data into whatever visual form is desired.
The Controller in a program contains the code that handles user interaction. It is the go-between for the Model and View. For example, if the user clicks on a chess piece, an event handler in the Controller would be called to handle the event.
There are several different implementations of the MVC design pattern. The one we will be using is illustrated below:
Back to our chess example. Let's say the user drags a Pawn from Location(1, 4) to Location(3, 4). Event handlers in the Controller would be called to handle the event and the Controller would work with the Model to decide what to do. The setOnMousePressed()
and setOnMouseReleased()
would work together to gather the information we need. Once we have collected all the information needed to process the event, our Controller would say something like this:
// Assume these variables have already been determined
Piece sourcePiece; // Piece being moved
Location sourceLoc; // Starting (row, col) of the Piece being moved
Location destLoc; // Ending (row, col) of the Piece being moved
// Ask the model questions and manipulate it
if (model.isValidMove(sourceLoc, destLoc)) {
model.makeMove(sourceLoc, destLoc);
}
else {
// Display "Invalid move" dialog box
}
}
When the Model changes as a result of the makeMove() function, the Model then tells the View what changed and the View updates its display.
Summary: The Controller handles user input and manipulates the Model. When the Model changes, it notifies the View so the display is refreshed.
To keep your program modular and resusable, the View should should not access the Model directly nor should it need to know the internal details of how information is stored.
For example, let's say our chess program uses integers to store piece types where 1 represents a pawn, 2 represents a knight, 3 represents a bishop, etc. Our model would have a 2D array of integers as shown below to represent the internal board:
int[][] board = {
{4, 2, 3, 5, 6, 3, 2, 4},
{1, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 1, 1},
{4, 2, 3, 5, 6, 3, 2, 4}
};
When the Model changes, it tells the View what happened:
Instead ofThe View class asks the model questions via method calls and translates the model data into a form the user sees in the GUI.
Last modified: March 06, 2023